Unity-Shader读书笔记(7)
透明效果
在实时渲染中要实现透明效果通常会在渲染模型的时候控制它
的透明通道(Alpha
Channel)。当开启透明混合后,当一个物体被渲染到屏幕上时,每个片元初了颜色值和深度值外,它还有另外一个属性——透明度。当透明度为1时,表示该像素完全不透明,而为0时,则表示该像素不会显示。
书中提供了两种方法实现透明效果(我不知道现在还有没有其他的方法):第一种是透明度测试(Alpha
Test)和透明度混合(Alpha Blending)。
渲染顺序
这里我们要强调一个概念就是渲染顺序。如果我们需要使用透明效果,那么我们就要考虑到场景中物体的渲染顺序。而不透明物体之所以不用考虑着一点是因为深度缓冲(depth
buffer,也称为z-buffer)的存在。在实时渲染中,深度缓冲是用于解决可见性(visibility)问题,它可以决定哪个物体的哪些部分被渲染在前面,而哪些部分会被其他物体遮挡。它的基本思想是:根据深度缓冲中的值来判断该片距离摄像机的距离。如果我们开启了深度测试。在我们渲染片元的时候,我们需要将它的深度值和深度缓冲中的深度值进行比较。如果它的深度值小于深度缓冲中的值(即比深度缓冲所存储的物体距离摄像机更远),那么就意味着这个片元不应该渲染到屏幕上(因为它被其他的物体遮挡住了)。否则这个片元应该覆盖掉此时颜色缓冲中的像素值。如果我们还开启了深度写入,那么深度缓冲中的数值也会被覆盖掉。所以如果我们使用了深度缓冲(开启深度测试和深度写入),那么我们无需关心物体间的渲染顺序。但是如果我们使用透明度混合得到透明效果就要关闭深度写入(ZWrite)。这样我们就必须考虑物体的渲染顺序了。
实现透明度的方法
接下来我简单概括一下透明度测试和透明度混合的原理。
透明度测试:对于一个片元,如果它的透明度不符合我们设立的条件。那么它就会被舍弃,不参与接下来的任何处理。正是因为这样所以透明度测试不需要关闭深度写入也无需在意渲染顺序。但是它很极端,经历透明度测试的片元要么完全透明(看不到),要么就不透明如同不透明的物体。
透明度混合:对于一个片元,透明度混合会以这个片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合得到新的颜色。透明度混合可以得到真正的半透明效果,但是它需要关闭深度写入。所以我们必须要考虑物体的渲染顺序了。不过要进行透明度混合的片元也是要先通过深度测试的。
Unity Shader的渲染顺序
Unity为了解决渲染顺序的问题提供了渲染队列(render
queue)。我们可以使用SubShader的Queue标签来决定我们的模型归于哪个渲染队列。具体大家可以看一下Unity官方文档的说明:ShaderLab:向子着色器分配标签
- Unity 手册(这里大家只要看Queue 标签哪里),RenderQueue
- Unity 脚本 API,Material-renderQueue
- Unity 脚本
API。书中还把对应的索引号表明了。但我觉得没有必要,这里我们只要知道越前面的越早渲染。你也可以从官网对起渲染队列的描述中看出来。
透明度测试
之前我们就提到所谓透明度测试就是将不满足条件的片元舍弃掉。而通常我们会使用clip函数来实现这个目标。(Unity中的clip应该是来自HLSL语义吗,我在Unity官网查找的时候查到的文章有说HLSL语义。我看到Unity官网文章为:着色器语义
- Unity
手册。大家全局搜索clip就可以看到这句话:如果值为负,则 clip
HLSL 指令停止渲染像素。而HLSL语义关于clip函数的介绍我也给大家clip
- Win32 apps | Microsoft
Learn。大家最好用英文看。因为中文只有机翻,我觉得很难受。)
具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| Shader "Learn/AlphaTestShader" { Properties { _Color ("Color",COLOR) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" {} _SpecularColor ("SpecularColor",Color) = (1,1,1,1) // 高光系数 _Gloss ("Gloss",Range(8,255)) = 20 // 裁剪值 _CutOff("Cut Off",Range(0,1)) = 0.5 } SubShader { Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}
Pass { Tags { "LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" #include "Lighting.cginc"
struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD2; };
float4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float4 _SpecularColor; fixed _Gloss; fixed _CutOff;
v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); //o.worldPos = mul(v.vertex,(float3x3)unity_WorldToObject); o.worldPos = mul(unity_ObjectToWorld,v.vertex); // 获取法线处于世界空间下的值,我们仍然只要得到单位向量 fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); o.worldNormal = worldNormal; // 计算得到纹理映射值 o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; return o; }
fixed4 frag (v2f i) : SV_Target { // 通过uv坐标得到纹理中的数组和设定的颜色值一起组成了该点的漫反射颜色值 fixed4 albedo = tex2D(_MainTex,i.uv).rgba; // 透明度测试 clip(albedo.a - _CutOff); albedo = albedo * _Color; // 获取到环境光 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; // 获取世界坐标系下灯光的单位向量 fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); // 得到反射光 fixed3 reflectDir = reflect(-worldLight,i.worldNormal); reflectDir = normalize(reflectDir); // 观察方向 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); // 计算得到漫反射值 fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(i.worldNormal,worldLight)); fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(saturate(dot(viewDir,reflectDir)),_Gloss); fixed3 color = ambient + diffuse + specular; //fixed3 color = specular; return fixed4(color,1); } ENDCG } }
FallBack "Transparent/Cutout/VertexLit" }
|
这里Shader仍然使用普通纹理映射的模板。其中我们在属性中增加了裁剪值。我们使用这个值来控制后面舍弃片元的条件。
之前我们就强调过渲染顺序的重要性。而我们如果要使用透明度测试,我们就要将渲染队列设置为AlphaTest队列。即标签中的Queue设置为AlphaTest。标签中的RenderType标签可以让Unity将这个Shader归入到提取定义的组(这里就是TransparentCutout),以指明该Shader是一个使用了透明度测试的Shader。我们还将IgnoreProjector设置为True,这意味着这个Shader不会受到投影器的影响。通常,使用了透明度测试Shader都要设置这三个标签。这里我再次给出对应的Unity官方文档的文章ShaderLab:向子着色器分配标签
- Unity 手册,在运行时替换着色器
- Unity 手册。
在片元函数中,我们让纹理的a通道(也就是表示透明度的值)和我们设定值相减。如果这个结果小于0,clip函数会直接停止渲染这个片元。
我们所使用的回调也被修改为"Transparent/Cutout/VertexLit"。这不仅能保证我们编写的SubShader无法在当前显卡上工作时可以有合适的代替Shader,还可以保证使用透明度测试的物体可以正确地向其他物体投射阴影。
透明度混合
透明度测试对待透明物体和不透明物体几乎是一样的,可透明度混合就不是这样的。透明度混合会将当前片元的透明度作为混合因子,与在颜色缓冲中的颜色进行混合得到新的颜色。但是透明度混合需要关闭深度写入,所以我们仍然要注意渲染的顺序。
这里我们需要用到一个新的命令——Blend。Blend是Unity提供的设置混合模式的命令。具体的关于Blend信息,可以看官网的介绍:ShaderLab
命令:Blend - Unity 手册,ShaderLab
命令:BlendOp - Unity 手册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| Shader "Learn/AlphaBlendShader" { Properties { _Color ("Color",COLOR) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" {} _SpecularColor ("SpecularColor",Color) = (1,1,1,1) _Gloss ("Gloss",Range(8,255)) = 20 _AlphaScale("AlphaScale",Range(0,1)) = 0.5 } SubShader { Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
Pass { Tags { "LightMode"="ForwardBase"}
ZWrite off Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" #include "Lighting.cginc"
struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD2; };
float4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float4 _SpecularColor; fixed _Gloss; fixed _AlphaScale;
v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld,v.vertex); fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); o.worldNormal = worldNormal; o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; return o; }
fixed4 frag (v2f i) : SV_Target { fixed4 texColor = tex2D(_MainTex,i.uv); fixed3 albedo = texColor.rgb * _Color; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); fixed3 reflectDir = reflect(-worldLight,i.worldNormal); reflectDir = normalize(reflectDir); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(i.worldNormal,worldLight)); fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(saturate(dot(viewDir,reflectDir)),_Gloss); fixed3 color = ambient + diffuse + specular; return fixed4(color,texColor.a * _AlphaScale); } ENDCG } }
FallBack "Transparent/VertexLit" }
|
透明度混合一定要关闭深度写入,我们这里就是使用ZWrite
off来实现深度写入。以下是Unity官网对于ZWrite的描述:ShaderLab
命令:ZWrite - Unity 手册。
如同透明度测试一样,我们在subShder中设置了对应的Tag来设置其渲染的队列、渲染的类型和是否忽略投影器。透明度混合也是一样,但是它们之间的设置是不一样的。透明度混合的设置如下:
1
| Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
|
如果要使用透明度混合就要这样设置。
blend的命令,我们则是使用Blend SrcAlpha OneMinusSrcAlpha,GPU
将此输入的值乘以(1 - 源
Alpha)。然后在最后输出的时候,我们使用_AlphaScale来控制纹理整体的透明度。
开启深度写入的半透明效果
我们使用透明度混合的时候就要将深度写入关闭掉,这里除了和其他物体之间渲染有问题,物体本身也会有问题互相叠加的情况。透明度混合和其他物体之间渲染可以通过渲染队列来解决,而物体本身的叠加问题就不能这样了。书中介绍了两种方法解决这个问题:“质量优等”的网格和重新使用深度写入。书中只是提及了“质量优等”的网格,所以这里就不进行过多的说明,大家要是有兴趣可以百度一下。
透明度混合是一定要关闭深度写入的,但是透明度混合仍然要进行深度测试。因此我们可以使用两个pass,第一个pass仅用来进行深度写入。第二个pass才进行透明度混合。这样透明度物体自身顶点就有了深度信息,有了深度信息就决定物体自身片元见的渲染顺序了。具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| Shader "Learn/AlphaBlendWithZwriteShader" { Properties { _Color ("Color",COLOR) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" {} _SpecularColor ("SpecularColor",Color) = (1,1,1,1) _Gloss ("Gloss",Range(8,255)) = 20 _AlphaScale("AlphaScale",Range(0,1)) = 0.5 } SubShader { Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
Pass { ZWrite On ColorMask 0 }
Pass { Tags { "LightMode"="ForwardBase"}
ZWrite off Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" #include "Lighting.cginc"
struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD2; };
float4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float4 _SpecularColor; fixed _Gloss; fixed _AlphaScale;
v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld,v.vertex); fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); o.worldNormal = worldNormal; o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; return o; }
fixed4 frag (v2f i) : SV_Target { fixed4 texColor = tex2D(_MainTex,i.uv); fixed3 albedo = texColor.rgb * _Color; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); fixed3 reflectDir = reflect(-worldLight,i.worldNormal); reflectDir = normalize(reflectDir); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(i.worldNormal,worldLight)); fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(saturate(dot(viewDir,reflectDir)),_Gloss); fixed3 color = ambient + diffuse + specular; return fixed4(color,texColor.a * _AlphaScale); } ENDCG } }
FallBack "Transparent/VertexLit" }
|
我们新增加了一个pass,在这个pass中我们启动了深度写入并使用ColorMask作为掩码。关于ColorMask大家可以看官网的说明:Unity
- Manual: ShaderLab command: ColorMask。
双面渲染的透明效果
在现实生活中,如果一个物体是透明的,这就意味着我们不仅仅可以透过它看到其他物的样子也可以看到它内部的模样。但是之前我们实现的效果都不能做到这点。因为默认情况下引擎都会剔除物体的背面(相对于摄像机的方向)。如果我们要实现双面渲染的效果,我们就要使用cull指令来控制剔除那个面的渲染图元。关于cull指令官网上是文章链接为:ShaderLab
命令:Cull - Unity 手册。
对于透明度测试而言,我们只需在透明度测试的Shader中加上cull
off就可以实现我们想要的效果。shader代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| Shader "Learn/BothSizeAlphaTestShader" { Properties { _Color ("Color",COLOR) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" {} _SpecularColor ("SpecularColor",Color) = (1,1,1,1) _Gloss ("Gloss",Range(8,255)) = 20 _CutOff("Cut Off",Range(0,1)) = 0.5 } SubShader { Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}
Pass { Tags { "LightMode"="ForwardBase"}
Cull Off
CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" #include "Lighting.cginc"
struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD2; };
float4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float4 _SpecularColor; fixed _Gloss; fixed _CutOff;
v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld,v.vertex); fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); o.worldNormal = worldNormal; o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; return o; }
fixed4 frag (v2f i) : SV_Target { fixed4 albedo = tex2D(_MainTex,i.uv).rgba; clip(albedo.a - _CutOff); albedo = albedo * _Color; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); fixed3 reflectDir = reflect(-worldLight,i.worldNormal); reflectDir = normalize(reflectDir); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(i.worldNormal,worldLight)); fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(saturate(dot(viewDir,reflectDir)),_Gloss); fixed3 color = ambient + diffuse + specular; return fixed4(color,1); } ENDCG } }
FallBack "Transparent/Cutout/VertexLit" }
|
而透明度混合就很麻烦了,因为透明度混合要关闭深度写入。这样我们就很难依照深度缓冲来保证渲染的正确性。不过我们仍然可以使用cull指令来帮助我们实现这个功能。一开始我们先渲染背面然后再渲染正面。这样我们就保证了渲染的正确性。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
| Shader "Learn/BothSizeAlphaBlendShader" { Properties { _Color ("Color",COLOR) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" {} _SpecularColor ("SpecularColor",Color) = (1,1,1,1) _Gloss ("Gloss",Range(8,255)) = 20 _AlphaScale("AlphaScale",Range(0,1)) = 0.5 } SubShader { Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
Pass { Tags { "LightMode"="ForwardBase"}
Cull Front ZWrite off Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" #include "Lighting.cginc"
struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD2; };
float4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float4 _SpecularColor; fixed _Gloss; fixed _AlphaScale;
v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld,v.vertex); fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); o.worldNormal = worldNormal; o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
return o; }
fixed4 frag (v2f i) : SV_Target { fixed4 texColor = tex2D(_MainTex,i.uv); fixed3 albedo = texColor.rgb * _Color; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); fixed3 reflectDir = reflect(-worldLight,i.worldNormal); reflectDir = normalize(reflectDir); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(i.worldNormal,worldLight)); fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(saturate(dot(viewDir,reflectDir)),_Gloss); fixed3 color = ambient + diffuse + specular; return fixed4(color,texColor.a * _AlphaScale); } ENDCG }
Pass { Tags { "LightMode"="ForwardBase"}
Cull Back ZWrite off Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" #include "Lighting.cginc"
struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD1; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD2; };
float4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float4 _SpecularColor; fixed _Gloss; fixed _AlphaScale;
v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld,v.vertex); fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); o.worldNormal = worldNormal; o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; return o; }
fixed4 frag (v2f i) : SV_Target { fixed4 texColor = tex2D(_MainTex,i.uv); fixed3 albedo = texColor.rgb * _Color; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); fixed3 reflectDir = reflect(-worldLight,i.worldNormal); reflectDir = normalize(reflectDir); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(i.worldNormal,worldLight)); fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(saturate(dot(viewDir,reflectDir)),_Gloss); fixed3 color = ambient + diffuse + specular; return fixed4(color,texColor.a * _AlphaScale); } ENDCG } }
FallBack "Transparent/VertexLit" }
|
此刻我们不能使用之前的方法先加使用一个Pass记录深度。如果我们先记录深度,cull
front就没有作用了。因为背面的片元是通过不了深度测试的。但是因为我们先渲染背面然后再渲染正面,正确的渲染顺序保证渲染的正确性。这时候我们可以不用之前的方法。