开启深度写入的半透明效果

作者:追风剑情 发布于:2016-10-24 19:54 分类:Shader

      前一篇文章给出了一种由于关闭深度写入而造成的错误排序的情况,一种解决方法是使用两个Pass来渲染模型:第一个Pass开启深度写入,但不输出颜色,它的目的仅仅是为了把该模型的深度值写入深度缓冲中;第二个Pass进行正常的透明度混合,由于上一个Pass已经得到了逐像素的正确的深度信息,该Pass就可以按照像素级别的深度排序结果进行透明渲染。但这种方法的缺点在于,多使用一个Pass会对性能造成一定的影响。使用这种方法,我们仍然可以实现模型与它后面的背景混合的效果,但模型内部之间不会有任何真正的半透明效果。

ZWrite On | Off 
控制深度缓冲写入 。
ColorMask RGB | A | 0 | 其他任何R、G、B、A的组合
控制颜色缓冲写入。当ColorMask设为0时,意味着该Pass不写入任何颜色通道,即不会输出任何颜色。

Shader代码

  1. Shader "Custom/Chapter8-AlphaBlendZWrite" {
  2. Properties {
  3. _Color ("Main Tint", Color) = (1, 1, 1, 1)
  4. _MainTex ("Base (RGB)", 2D) = "white" {}
  5. _AlphaScale ("Alpha Scale", Range(0, 1)) = 1
  6. }
  7. SubShader {
  8. //RenderType标签通常被用于着色器替换功能。
  9. Tags { "Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent" }
  10. LOD 200
  11. Pass {
  12. //这个新添加的Pass的目的仅仅是为了把模型的深度信息写入深度缓冲中,
  13. //从而剔除模型中被自身遮挡的片元。
  14. //开启深度缓冲写入
  15. ZWrite On
  16. //关闭颜色缓冲写入
  17. ColorMask 0
  18. }
  19. Pass {
  20. Tags {"LightMode"="ForwardBase"}
  21. ZWrite Off
  22. Blend SrcAlpha OneMinusSrcAlpha
  23. CGPROGRAM
  24. #pragma vertex vert
  25. #pragma fragment frag
  26. #include "UnityCG.cginc"
  27. #include "Lighting.cginc"
  28. fixed4 _Color;
  29. sampler2D _MainTex;
  30. float4 _MainTex_ST;
  31. //用于在透明纹理的基础上控制整体的透明度。
  32. fixed _AlphaScale;
  33. struct a2v {
  34. float4 vertex : POSITION;
  35. float3 normal : NORMAL;
  36. //Unity会将模型的第一组纹理坐标存储到该变量中
  37. float4 texcoord : TEXCOORD0;
  38. };
  39. struct v2f {
  40. float4 pos : SV_POSITION;
  41. float3 worldNormal : TEXCOORD0;
  42. float3 worldPos : TEXCOORD1;
  43. float2 uv : TEXCOORD2;
  44. };
  45. v2f vert(a2v v) {
  46. v2f o;
  47. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
  48. o.worldNormal = mul(v.normal, (float3x3)_World2Object);
  49. //Unity5中可用UnityObjectToWorldNormal()函数得到o.worldNormal
  50. //o.worldNormal = UnityObjectToWorldNormal(v.normal);
  51. o.worldPos = mul(_Object2World, v.vertex).xyz;
  52. o.uv = v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
  53. //或者调用Unity内建的函数计算o.uv
  54. //o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  55. return o;
  56. }
  57. fixed4 frag(v2f i) : COLOR {
  58. fixed3 worldNormal = normalize(i.worldNormal);
  59. //fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
  60. fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//只适合场景中仅有一个平行光
  61. fixed4 texColor = tex2D(_MainTex, i.uv);
  62. fixed3 albedo = texColor.rgb * _Color.rgb;
  63. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
  64. fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
  65. //只有使用Blend命令打开混合后,我们在这里设置透明通道才有意义,
  66. //否则,这些透明度并不会对片元的透明效果有任何影响。
  67. //透明通道: 纹理像素的透明通道和材质参数_AlphaScale的乘积。
  68. return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
  69. }
  70. ENDCG
  71. }
  72. }
  73. //确保我们编写的SubShader无法在当前显卡上工作时可以有合适的代替Shader,
  74. //还可以保证使用透明度测试的物体可以正确地向其他物体投射阴影
  75. FallBack "Transparent/Cutout/VertexLit"
  76. }

效果

111111.png

标签: Shader

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号