——20.8.18

Unity中,通常用两种方法来实现透明效果 1)透明度测试 2)透明度混合 这两个分别是什么呢

1.透明度测试指的只要不符合条件(即在物体颜色中的alpha通道的值小于某一个阈值)对应片元会被直接舍弃。(该片元不会对颜色缓冲有任何影响)否则就按照不透明物体处理。进行深度测试和深度写入。特点:不关闭深度写入 没法做到半透明要么不透明要么全透明

2.透明度混合指的是使用当前片元透明度为混合因子于已经储存的在颜色缓存中的颜色进行混合。要关闭深度写入不关闭深度测试。通过深度测试能够正确的确定非透明物体于透明物体之间的覆盖关系。 特点:关闭深度写入 做到半透明

在我们对上面两个定义进行下一步解读之前先回顾两个概念 深度写入以及深度测试 两者发生的过程是在GPU渲染的时候发生的,即下面这张图的关系

深度测试就是通过摄像机与该片元的距离(也就是深度)于之前存在深度缓存区的深度值进行比较 对应的条件来决定是否舍弃该片元 ZTest

深度写入则是是否要将深度测试的结果覆盖到深度缓存区中 因为半透明物体的存在是不可以作为深度的标准来舍弃因为半透明物体与其他物体是叠加的关系的 ZWrite

接着我们就可以引入一个新的重要性的问题 就是渲染顺序 这是在Tags中的一个元素 “Queue”

因为我们对半透明物体关闭了深度写入的操作 则对我们的渲染顺序有一定的要求也就是在关闭了深度写入的条件下渲染顺序的正确与否便是十分重要因为会引发两个问题 1)对非透明物体与半透明物体之间 因为关闭了深度写入,当半透明物体先渲染由于深度缓存为空则非透明物体直接覆盖 2)半透明物体与半透明物体之间 渲染顺序如果与深度一致(由近到远)则导致看上去位置相反

常用方法:1.先渲染所有不透明物体开启深度测试与写入(“Queue”=“Geometry”) 2.把半透明物体由远到近顺序渲染 并开启深度测试关闭写入(“Queue”=“AlphaTest“)

但依旧还是有问题所以才叫做混乱的开端 因为存在重叠现象一个物体有两个渲染顺序(每个像素都有深度,逐像素去遍历无法选取) 便采取分割网格 并且务必使用凸面体 需要具体问题具体分析

下面就是久违的ShaderLab部分了,我的想法是坚决不做搬运工,下面的部分直接选取部分代码说自己的理解 还是要自己敲一遍 最后再上源码 虽然上面部分就是书上的用我的理解包括一些大佬的理解顺序也很像书上的顺序 就是慢慢改进吧 嘿嘿

一、透明度测试

void Clip(x) x:float4,float3,flaot2,float
void Clip(float4 x)
{
  if(any(x < 0))
    discard;
}

  参数x是裁剪时所使用的标量或矢量

  如果给定参数的任何一个分量是负数则直接舍弃该像素

Tags { "RenderType"="TransparentCutOut" "Queue"="AlphaTest" "IgnoreProjector"="True" }

  样例给的要点主要有要在SubShader中设置”Queue“为了透明度测试 ”IgnoreProjector“为了设置不受到投影器的影响

clip(texColor.a - _Cutoff);

  内部参数为原图像的透明度减去_Cutoff(为能接受的阈值) 当这个值小于0则直接discard

源码:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unlit/8-1AlphaTest"
{
Properties
{
_Color("Color", Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
}
SubShader
{
Tags { "RenderType"="TransparentCutOut" "Queue"="AlphaTest" "IgnoreProjector"="True" }
Pass
{
Tags{ "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
fixed _Cutoff; v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
} fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
clip(texColor.a - _Cutoff);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0 * albedo * saturate(dot(worldNormal, worldLightDir));
return fixed4(diffuse + ambient, 1.0);
}
ENDCG
}
}FallBack "Transparent/Cutout/VertexLit"
}

  

二、透明度混合

说到混合就要讲混合指令Blend

采用的是以下的公式 源颜色就是该片元的颜色 目标颜色就是颜色缓存的颜色

ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

  要关闭深度写入 同时开启混合(设置的时候即开启)如果不打开blend默认是关闭的就以深度测试的结构决定直接覆盖A=1(?没找到依据但实验结果如此)

源码:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unlit/8-2AlphaBlend"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_AlphaScale ("AlphaScale", Range(0,1)) = 1
}
SubShader
{
Tags { "RenderType"="Transparent" "IgnoreProjector"="True" "Queue"="Transparent" }
Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
fixed _AlphaScale; v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
} fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal, worldLightDir));
return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
}
ENDCG
}
}FallBack "Transparent/VertexLit"
}

三、开启深度写入的半透明

我们可以看一下上面这个图可以发现这个图全露出就是当模型存在互相交叉的时候会得到这样错误的效果 本质的原因就是没有打开深度写入导致的单物体内部错误 那有什么解决方方能就是用双Pass 第一个Pass把最前面的输出片元的深度值通过比较后存入深度缓存中但不输出颜色 第二个Pass再关闭深度写入 可以直接和正确的比较直接discard

ColorMask 0 | RGB | G |

  设置颜色通道的写掩码就是指定输出的颜色通道 0就是不输出

源码:

Shader "Unlit/8-3AlphaBlendZWrite"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_AlphaScale ("AlphaScale", Range(0, 1)) = 1
}
SubShader
{
Tags { "RenderType"="Transparent" "IgnoreProjector"="True" "Queue"="Transparent" } Pass{
ZWrite On
ColorMask 0
} Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
//Alpha Blend
Blend SrcAlpha OneMinusSrcAlpha
//Soft Additive
//Blend OneMinusDstColor One
//Multiply
//Blend DstColor Zero
//Multiply 2X
//Blend DstColor SrcColor
//Darken
//BlendOp min
//Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
fixed _AlphaScale; v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
} fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal, worldLightDir));
return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
}
ENDCG
}
}FallBack "Diffuse"
}

  

这张图有一点奇怪就是存在投影。可以看Cp9的半透明投影部分主要是FallBack设置。

四、双面渲染的透明效果

这个是最后的内容啦 加加油 也就是剔除渲染图元的关系默认的情况下为了节约资源只渲染证明不渲染背面我们则需要用指令打开

Cull off | back | Front

  设置back不渲染back 设置off就是都渲染

那么对应的透明度测试的双目渲染我直接放图代码便是在以上基础上在Pass里面添加以上指令

可以明显对比

然后就是透明度混合的双目渲染 比上述的麻烦了一点就是双Pass 先渲染背面后渲染正面因为从视角看上去避免了之前说的半透明物体与半透明物体之间因为渲染顺序的导致的问题可以直接比较一下 毕竟图形学是效果的学科看看啥效果就知道了

可以很明显看出第二个比第一个有了对面的背面(奇妙的比喻)也就是双目渲染 第三个则是渲染顺序相反背面先渲染 摄像机进入物体能看到颜色鲜艳的正面

最后最后留个小坑就是BlendOp 我也没太看懂可能需要具体例子才会用吧 只有一些效果

谢谢你看到最后 cheers!

ps.刚刚看完Shader入门Cp8记录记录一些细碎的知识点以及相关深度研究学习

一切混乱开端的透明效果——ShaderCp8的更多相关文章

  1. Unity Shader入门精要学习笔记 - 第8章 透明效果

    转载自 冯乐乐的 <Unity Shader入门精要> 透明是游戏中经常要使用的一种效果.在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道.当开启透明混合后,当一个物体被渲染 ...

  2. Android课程---Android设置透明效果的三种方法(转)

    1.使用Android系统自带的透明效果资源 <Button  android:background="@android:color/transparent"/>   ...

  3. Unity3D ShaderLab 使用alpha参数创建透明效果

    Unity3D ShaderLab 使用alpha参数创建透明效果 其实Unity为了方便我们的工作,为我们内置了很多参数.比如马上用到的透明功能. 准备场景新建Shader Material ,一张 ...

  4. 用CSS实现Firefox 和IE 都支持的Alpha透明效果

    有的时候,为了实现一些特殊效果,需要将页面元素变透明,本文介绍的就是用 CSS 实现 Firefox 和 IE 都支持的 Alpha 透明效果.CSS: filter:alpha(opacity=50 ...

  5. 一些有用的 Emacs 配置(窗口快速切换、一键透明效果、任意位置删除整行等)

    本篇文章记录的是一些有用的 Emacs 配置,有些是自己原创,有些是借鉴别人(能记起来出处的我放了链接). 规定:C 代表 Ctrl,M 代表 Alt. 1.设置一次跳跃 n 行的快捷键 按 C-M- ...

  6. Css实现透明效果,兼容IE8

    Css实现透明效果,兼容IE8 >>>>>>>>>>>>>>>>>>>>> ...

  7. CentOS下Qt窗口透明效果失效,成黑色背景的问题

    一.问题 Linux系统下Qt窗口的透明效果成了黑色,但同样的代码在windows机子上有透明效果,主要是修改系统的配置,仅在centos6.3及其以上版本实验过.其他系统可以相应配置. 二.问题运行 ...

  8. QT下的几种透明效果(三种方法:调色板,透明度属性,自绘)

    1.窗口整体透明,但是窗体上的控件不透明.    通过设置窗体的背景色来实现,将背景色设置为全透.  QPalette pal = palette();  pal.setColor(QPalette: ...

  9. android:android:background="#00000000",透明效果

    ImageButton中设置 android:background="#00000000",可以达到透明效果 具体的源码 管理-->文件中的 viewpager0829.ra ...

  10. Windows窗体透明效果

    虚拟机里的win7也想实现透明效果, 使用vitrite这个免费软件就可以了.

随机推荐

  1. 使用EmguCV3.0.0调用摄像头并设置帧率

    此教程使用emgu3.0.0,其他版本兼容性未知. 转载请注明出处: http://www.cnblogs.com/zaiyuzhong/p/open-camera-with-emgu3_0_0.ht ...

  2. 2023-03-01 Warning: require(C:\wamp\www\tp5\public../thinkphp/base.php): failed to open stream: No such file or directory in C:\wamp\www\tp5\public\index.php on line 15

    问题描述:拉取thinkphp5项目来运行,按照官网的提示都拉取完仓库后,在浏览器访问localhost/tp5/public报错: Warning: require(C:\wamp\www\tp5\ ...

  3. 19_webpack_externals

    假如我们购买了CDN服务器为我们的网站的访问速度进行优化,那么我们,该如何配置 假如我的CDN为:https://mr-hou88888/cdn/那么publicPath该如何配置 1.配置publi ...

  4. 《在编译两个不同的库时,不想相互include头文件,但又需要用到对方的函数,可以用extern》

    以下是个人理解,水平有限,可能不太准确.有问题,麻烦指出. demo: a.so void a_fun(void) { b_fun(); } b.so void b_fun(void) { //略 } ...

  5. python随机数模拟

    `#随机数 import random red = range(1,36,1) red_target_list=[] i=1 while i< 6: red_ran_index=random.r ...

  6. VSCode 抽取vue的代码片段

    在vscode中文件-->首选项-->用户片段,输入名字按去确定,输入代码片段 { "vue htm": { "scope": "html ...

  7. 阿里云IPSec的一些问题

    1.阿里云IPSec无法进行多段连接单个IPSec连接 解决方案  在阿里云端需要如下操作 1.单个VPN网关下创建多个IPSec连接  连接属性一致  使用兴趣流模式.打开nat转换.  2段对2段 ...

  8. Cleanest XMaster绿色解压最新版下载9.6密钥激活码

    cad安装报错换了好几个版本都不行,用这个卸载了一下,确实有用 Cleanest XMaster绿色版cad卸载工具分享下载 地址一(百度网盘) 地址二(直接下载) 9.6.05密钥:[AtrXShX ...

  9. Demo of canvas, canvas optimization and svg

    It used the canvas to draw the curves in the old project, and the client felt that it was vague, so ...

  10. flink udaf函数

    1.Flink-sql自定义UDAF函数 - 简书 (jianshu.com) 2.Flink SQL 自定义UDAF_k_wzzc的博客-CSDN博客_flink udaf 3.Flink 实践教程 ...