当前位置:   article > 正文

unity shader 入门 全透明与半透明效果实现_unity alpha cutoff

unity alpha cutoff

片元函数的fixed4类型的返回值的第4位即为阿尔法值,0代表完全不显示(透明),1代表完全显示。中间的数值代表半透明。但只修改这个值是不能直接修改透明度的,因为还要对队列等进行修改。

本文介绍透明度测试与透明度混合,前者只能制作全透明效果,后者可制作半透明效果。

透明度测试/全透明效果:

如果要将纹理贴图的一部分显示为不透明,另一部分显示为完全透明,可以使用这个方法。方法很简单,在片元函数中加入如下内容:

if((texColor.a - _Cutoff)<0)//条件根据需要改
{
    discard;//剪除、不显示该片元
}

这里的_Cutoff是设置的一个可以修改的系数,texColor.a为纹理贴图的阿尔法通道。当满足条件(texColor.a- _Cutoff)<0)时剪除该片元,也就是完全透明。具体条件可根据需要改。

同时建议使用标签Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" },含义分别为选择渲染队列为AlphaTest(在渲染不透明物体之后、透明物体之前渲染该物体);不产生阴影;

一个透明度测试/全透明效果的完整例子:

  1. Shader "Test"
  2. {
  3. Properties
  4. {
  5. _MainTex("MainTex", 2D) = "white" {}//纹理贴图
  6. _Diffuse("Diffuse", Color) = (1,1,1,1)//漫反射颜色
  7. _Cutoff("Alpha Cutoff", Range(0,1)) = 0.5//设置的控制透明部分的系数
  8. }
  9. SubShader
  10. {
  11. Tags {
  12. "Queue"="AlphaTest" //在不透明物体之后、透明物体之前渲染该物体;
  13. "IgnoreProjector"="True" //不产生阴影;
  14. }
  15. LOD 100
  16. Pass
  17. {
  18. CGPROGRAM
  19. #pragma vertex vert
  20. #pragma fragment frag
  21. #include "UnityCG.cginc"
  22. #include "Lighting.cginc"
  23. sampler2D _MainTex;
  24. float4 _MainTex_ST;
  25. fixed4 _Diffuse;
  26. float _Cutoff;
  27. struct v2f
  28. {
  29. float4 vertex : SV_POSITION;
  30. fixed3 worldNormal: TEXCOORD0;//世界空间法线
  31. float3 worldPos: TEXCOORD1;//世界空间顶点坐标
  32. float2 uv : TEXCOORD2;//uv坐标
  33. };
  34. v2f vert (appdata_base v)//appdata_base是自带的一个结构体,含有vertex、normal等的定义,这样就不用自己再定义一个类似的结构体了。
  35. {
  36. v2f o;
  37. o.vertex = UnityObjectToClipPos(v.vertex);
  38. fixed3 worldNormal = UnityObjectToWorldNormal( v.normal);
  39. o.worldNormal = worldNormal;
  40. o.worldPos = mul(unity_ObjectToWorld, v.vertex);
  41. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  42. return o;
  43. }
  44. fixed4 frag (v2f i) : SV_Target
  45. {
  46. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光
  47. fixed4 texColor = tex2D(_MainTex, i.uv);//读取纹理贴图颜色值
  48. if((texColor.a - _Cutoff)<0)//满足条件时不显示该片元,这里的条件为纹理贴图的α通道的值小于_Cutoff
  49. {
  50. discard;//剪除、不显示该片元
  51. }
  52. //漫反射
  53. fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos);
  54. fixed3 diffuse = _LightColor0.rgb * texColor.rgb * _Diffuse.rgb * (dot(worldLightDir,i.worldNormal)*0.5+0.5);
  55. fixed3 color = ambient + diffuse;
  56. return fixed4(color,1);
  57. }
  58. ENDCG
  59. }
  60. }
  61. FallBack "VertexLit"//虽然之前的标签了设置了不产生阴影,但FallBack的方案也会产生阴影
  62. }

使用一张渐变的一半透明的纹理贴图,调整_Cutoff可以调整透明的面积。

制作草时可以使用透明度测试让贴图除草之外的部分全透明。但使用这个方法只能得到全透明的效果,而不能产生半透明的效果。

 透明度混合/半透明效果:

先讲几个概念:深度测试、深度写入、深度缓存、颜色缓存。

在渲染时都要进行深度测试,当渲染不透明物体时,将深度与深度缓存中的值比较,发现新片元更靠近摄像机时,就将新深度写入深度缓存,并更新颜色缓存。这样最后渲染出的颜色就是最接近摄像机的片元的颜色,被其遮挡的则不会渲染。

渲染半透明物体,需要在不透明物体渲染结束后。渲染半透明物体依然会进行深度测试,剔除掉被不透明物体遮挡的片元。但需要关闭深度写入,不再更新深度缓存。发现是需要渲染的颜色时,不是直接替换颜色缓冲,而是以一定方式进行混合。下面是一些常见混合类型,和ps中的图层叠加比较相似:

常见混合操作类型:

//正常(Normal)透明度混合

Blend SrcAlpha OneMinusSrcAlpha

//柔和相加

Blend OneMinusDstColor One

//正片叠底

Blend DstColor Zero

//两倍相乘

Blend DstColor SrcColor

//变暗

BlendOp min

Blend One One

//变亮

Blend OneMinusDstColor One

Blend One OneMinusSrcColor

//线性减淡

Blend One One

通常,半透明shader都有如下3个标签:
        Tags { 
            "Queue"="Transparent" //选择渲染队列为Transparent,这样会在渲染不透明物体之后再渲染该物体
            "IgnoreProjector"="True" //不受阴影投射器影响
            "RenderType"="Transparent"//将该shader归入预先设置的类Transparent,这个标标签的功能常被用于shader替换
            }

并且需要在pass中关闭深度写入和选择颜色混合方案:

            ZWrite Off //关闭深度写入
            Blend SrcAlpha OneMinusSrcAlpha //颜色混合方案

一个完整的代码例子:

  1. Shader "Test"
  2. {
  3. Properties
  4. {
  5. _MainTex("MainTex", 2D) = "white" {}
  6. _Diffuse("Diffuse", Color) = (1,1,1,1)
  7. _AlphaScale("Alpha Scale", Range(0,1)) = 1//透明度系数,0表示完全透明
  8. }
  9. SubShader
  10. {
  11. //半透明shader通常都包含这3个标签
  12. Tags {
  13. "Queue"="Transparent" //选择渲染队列为Transparent,这样会在渲染不透明物体之后再渲染该物体
  14. "IgnoreProjector"="True" //不受阴影投射器影响
  15. "RenderType"="Transparent"//将该shader归入预先设置的类,常被用于shader替换
  16. }
  17. LOD 100
  18. ZWrite Off //关闭深度写入
  19. Blend SrcAlpha OneMinusSrcAlpha //开启普通混合
  20. Pass
  21. {
  22. Tags{"LightMode"="ForwardBase"}//光照模式
  23. CGPROGRAM
  24. #pragma vertex vert
  25. #pragma fragment frag
  26. #include "UnityCG.cginc"
  27. #include "Lighting.cginc"
  28. sampler2D _MainTex;
  29. float4 _MainTex_ST;
  30. fixed4 _Diffuse;
  31. float _AlphaScale;
  32. struct v2f
  33. {
  34. float4 vertex : SV_POSITION;
  35. fixed3 worldNormal: TEXCOORD0;
  36. float3 worldPos: TEXCOORD1;
  37. float2 uv : TEXCOORD2;
  38. };
  39. v2f vert (appdata_base v)
  40. {
  41. v2f o;
  42. o.vertex = UnityObjectToClipPos(v.vertex);
  43. fixed3 worldNormal = UnityObjectToWorldNormal( v.normal);
  44. o.worldNormal = worldNormal;
  45. o.worldPos = mul(unity_ObjectToWorld, v.vertex);
  46. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  47. return o;
  48. }
  49. fixed4 frag (v2f i) : SV_Target
  50. {
  51. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光颜色
  52. fixed4 texColor = tex2D(_MainTex, i.uv);//纹理贴图颜色
  53. //漫反射
  54. fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos);
  55. fixed3 diffuse = _LightColor0.rgb * texColor.rgb * _Diffuse.rgb * (dot(worldLightDir,i.worldNormal)*0.5+0.5);
  56. fixed3 color = ambient + diffuse;
  57. return fixed4(color, texColor.a * _AlphaScale);//使用纹理贴图的阿尔法通道*_AlphaScale作为新阿尔法值,0为全透明
  58. }
  59. ENDCG
  60. }
  61. }
  62. FallBack "VertexLit"
  63. }

半透明物体的背面信息也被剔除了,所以是不会显示的。如果需要显示背面信息,在pass中使用Cull Off关闭剔除。如果需要先渲染背面内容,再渲染正面内容,以便从前到后正确混合颜色,就将pass复制为2个,上方的pass用Cull Front只渲染背部,下方的pass用Cull Back只渲染前部。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/126886
推荐阅读
相关标签
  

闽ICP备14008679号