• 【图形学】26 透明效果基础


    来源:《UNITY SHADER入门精要》

    1、透明度测试

      透明度测试(Alpha Test),这出来的效果不是真的透明,而更像是会使得物体的一部分消失。通过设置一个 Alpha 通道的阈值,不满足条件的片元就直接舍弃,这样,一个物体可能就不会完全的显示。

    2、透明度混合

      透明度混合(Alpha Blending),这种方法可以得到真正的半透明效果,它会使用当前已有的片元颜色 和 透明度值 进行混合,得到新的颜色。
      开启了透明度混合就一定要关闭深度写入,所以必须注意渲染顺序,否则会让透明的物体不会因为在前面而遮挡致使不透明的物体不画。同时,对于透明混合来说,深度缓冲只是只读的。

      为了使得半透明的效果正常,我们会对物体的渲染顺序进行排序,然后再渲染:
    (1)先渲染所有不透明的物体,此时开启他们的深度测试和深度写入。
    (2)对于半透明的物体,按照离摄像机的远近进行排序,然后从后往前渲染这些半透明的物体,此时开启它们的深度测试,但是关闭深度写入。

    3、UnityShader的渲染队列

      为了解决渲染顺序问题,Unity 提供了**渲染队列(Render Queue)**这一解决方案。我们可以使用 SubShader Tags 设置为 AlphaTest 或者 Transparent 来决定我们的模型处于哪个渲染队列。序号越小,越早被渲染。例子:

    SubShader{
    	Tags { "Queue" = "Transparent" }
    	Pass {
    		ZWrite Off
    		//..
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TOqe8yzR-1663118270470)(assets/image-20220624172932425.png)]

    4、半透明测试的代码解读

    Shader "Unity Shaders Book/Chapter 8/Alpha Test" {
    	Properties {
    		_Color ("Color Tint", Color) = (1, 1, 1, 1)
    		_MainTex ("Main Tex", 2D) = "white" {}
    		_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

      为了减少负担,我们这里不再进行光照的计算,仅仅是采样贴图纹理,然后设置 Alpha Test 的阈值。

    	SubShader {
    		Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    				Pass {
    			Tags { "LightMode"="ForwardBase" }
    
    • 1
    • 2
    • 3
    • 4

      这里的 Tags 设置的比较多,第一个,Queue 设置为 AlphaTest,指明了这个 SubShader 使用了透明度测试。
      第二个,我们设置 IgnoreProjector 为 True。意味着这个 Shader 不会受到 投影器(Projectors)的影响,也就是说,不会被其他物体打上阴影。
      第三个,RenderType可以把这个 SubShader 设置提前定义的组中,这里是 TransparentCutout 组中。
      最后,我们在 Pass 中定义了 LightMode 的方式为 ForwardBase。这样,我们定义了这个 Pass 在光照流水管线中的角色。只有定义了正确的 LightMode,我们才能正确的到一些 Unity 的内置光照变量,例如 _LightColor0

      通常我们进行 透明度测试 的 Shader 都应该在 SubShader 中设置这三个标签。

    			CGPROGRAM
    			
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "Lighting.cginc"
    			
    			fixed4 _Color;
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			fixed _Cutoff;
    			
    			struct a2v {
    				float4 vertex : POSITION;
    				float3 normal : NORMAL;
    				float4 texcoord : TEXCOORD0;
    			};
    			
    			struct v2f {
    				float4 pos : SV_POSITION;
    				float3 worldNormal : TEXCOORD0;
    				float3 worldPos : TEXCOORD1;
    				float2 uv : TEXCOORD2;
    			};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

      很简单,没啥好说的,没有新加变量。

    			v2f vert(a2v 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;
    			}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

      顶点着色器所做的事情不过是空间的转换而已

    			fixed4 frag(v2f i) : SV_Target {
    				fixed3 worldNormal = normalize(i.worldNormal);
    				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    				
    				fixed4 texColor = tex2D(_MainTex, i.uv);
    				
    				// Alpha test
    				clip (texColor.a - _Cutoff);
    				// Equal to 
    //				if ((texColor.a - _Cutoff) < 0.0) {
    //					discard;
    //				}
    				
    				fixed3 albedo = texColor.rgb * _Color.rgb;
    				
    				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    				
    				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
    				
    				return fixed4(ambient + diffuse, 1.0);
    			}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

      与之前不一样的地方是:这里没有计算高光,这里用 clip() 裁剪之后的 texColor 来计算反射率。

    			ENDCG
    		}
    	} 
    	FallBack "Transparent/Cutout/VertexLit"
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    日期相关整理
    PCL 源码分析:ICP点云精配准
    带你一张图了解八种流行的网络协议
    04747 java程序设计笔记 --多线程
    聊聊微服务架构思想
    rsync+inotify实时同步+双向同步
    AR空间音频能力,打造沉浸式声音体验
    Unity布料系统_Cloth组件(包含动态调用相关)
    LeetCode简单题之判断两个事件是否存在冲突
    GD32F30x系列Systick系统滴答定时器 (Qt模拟项目 可套函数模板)
  • 原文地址:https://blog.csdn.net/qq_40891541/article/details/126845866