精华内容
下载资源
问答
  • shader显示透明
    2022-08-01 17:05:30

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

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

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

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

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

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

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

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

    Shader "Test"
    {
         Properties
    	{
    		_MainTex("MainTex", 2D) = "white" {}//纹理贴图
    		_Diffuse("Diffuse", Color) = (1,1,1,1)//漫反射颜色
    		_Cutoff("Alpha Cutoff", Range(0,1)) = 0.5//设置的控制透明部分的系数
    	}
    
    	SubShader
    	{
    		Tags { 
    			"Queue"="AlphaTest" //在不透明物体之后、透明物体之前渲染该物体;
    			"IgnoreProjector"="True" //不产生阴影;
    			}
    		LOD 100
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			#include "UnityCG.cginc"
    			#include "Lighting.cginc"
    
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			fixed4 _Diffuse;
    			float _Cutoff;
    
    			struct v2f
    			{
    				float4 vertex : SV_POSITION;
    				fixed3 worldNormal: TEXCOORD0;//世界空间法线
    				float3 worldPos: TEXCOORD1;//世界空间顶点坐标
    				float2 uv : TEXCOORD2;//uv坐标
    			};
    
    			v2f vert (appdata_base v)//appdata_base是自带的一个结构体,含有vertex、normal等的定义,这样就不用自己再定义一个类似的结构体了。
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				fixed3 worldNormal = UnityObjectToWorldNormal( v.normal);
    				o.worldNormal = worldNormal;
    				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    				return o;
    			}
    			
    			fixed4 frag (v2f i) : SV_Target
    			{
    				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光
    				fixed4 texColor = tex2D(_MainTex, i.uv);//读取纹理贴图颜色值
    
    				if((texColor.a - _Cutoff)<0)//满足条件时不显示该片元,这里的条件为纹理贴图的α通道的值小于_Cutoff
    				{
    					discard;//剪除、不显示该片元
    				}
    
    				//漫反射
    				fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos);
    				fixed3 diffuse = _LightColor0.rgb * texColor.rgb * _Diffuse.rgb * (dot(worldLightDir,i.worldNormal)*0.5+0.5);
    
    				fixed3 color = ambient + diffuse;
    				return fixed4(color,1);
    			}
    			ENDCG
    		}
    	}
    	FallBack "VertexLit"//虽然之前的标签了设置了不产生阴影,但FallBack的方案也会产生阴影
    }
    

    使用一张渐变的一半透明的纹理贴图,调整_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 //颜色混合方案

    一个完整的代码例子:

    Shader "Test"
    {
          Properties
    	{
    		_MainTex("MainTex", 2D) = "white" {}
    		_Diffuse("Diffuse", Color) = (1,1,1,1)
    		_AlphaScale("Alpha Scale", Range(0,1)) = 1//透明度系数,0表示完全透明
    	}
    
    	SubShader
    	{
    		//半透明shader通常都包含这3个标签
    		Tags { 
    			"Queue"="Transparent" //选择渲染队列为Transparent,这样会在渲染不透明物体之后再渲染该物体
    			"IgnoreProjector"="True" //不受阴影投射器影响
    			"RenderType"="Transparent"//将该shader归入预先设置的类,常被用于shader替换
    			}
    		LOD 100
    		ZWrite Off //关闭深度写入
    		Blend SrcAlpha OneMinusSrcAlpha //开启普通混合
    
    
    		Pass
    		{
    			Tags{"LightMode"="ForwardBase"}//光照模式
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			#include "UnityCG.cginc"
    			#include "Lighting.cginc"
    
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			fixed4 _Diffuse;
    			float _AlphaScale;
    
    			struct v2f
    			{
    				float4 vertex : SV_POSITION;
    				fixed3 worldNormal: TEXCOORD0;
    				float3 worldPos: TEXCOORD1;
    				float2 uv : TEXCOORD2;
    			};
    
    			v2f vert (appdata_base v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				fixed3 worldNormal = UnityObjectToWorldNormal( v.normal);
    				o.worldNormal = worldNormal;
    				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    				return o;
    			}
    			
    			fixed4 frag (v2f i) : SV_Target
    			{
    				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光颜色
    
    				fixed4 texColor = tex2D(_MainTex, i.uv);//纹理贴图颜色
    
    				//漫反射
    				fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos);
    				fixed3 diffuse = _LightColor0.rgb * texColor.rgb * _Diffuse.rgb * (dot(worldLightDir,i.worldNormal)*0.5+0.5);
    
    				fixed3 color = ambient + diffuse;
    				return fixed4(color, texColor.a * _AlphaScale);//使用纹理贴图的阿尔法通道*_AlphaScale作为新阿尔法值,0为全透明
    			}
    			ENDCG
    		}
    	}
    	FallBack "VertexLit"
    }
    

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

    更多相关内容
  • Unity Shader 之遮挡透明

    2022-04-05 19:28:31
    Unity Shader 之遮挡透明
  • unity3D panel面片正反双面可显示不同纹理,带透明通道图片的 shader 正反两面都可设置纹理图
  • unity玻璃双面透明显示材质shader

    热门讨论 2015-06-10 15:12:29
    解决三维模型导入unity中,玻璃双面透明显示的材质问题。
  • Unity Shader 被遮挡的部分半透高亮显示
  • Unity Shader透明效果

    千次阅读 2022-02-16 16:53:04
    透明度为1时表示该像素是完全不透明的,当为0时,则表示像素完全不会显示。 在unity中,我们通常使用两种方法来实现透明效果:第一种是使用透明度测试,这种方法其实无法得到真正的半透明效果;另一种就是透明度...

    在实时渲染中要实现透明效果,通常会在渲染模型时控制他的透明通道。当开启透明混合后,当一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值之外,它还有另一个属性——透明度。当透明度为1时表示该像素是完全不透明的,当为0时,则表示像素完全不会显示。

    在unity中,我们通常使用两种方法来实现透明效果:第一种是使用透明度测试,这种方法其实无法得到真正的半透明效果;另一种就是透明度混合。

    对于不透明物体,不考虑他们的渲染顺序也能得到正确的排序效果,这是由于强大的深度缓冲的存在。在实时渲染中,深度缓冲是用于解决可见性问题的,它可以决定那个物体的那些部分会被渲染在前面,那些部分会被其他物体遮挡。他的基本思想是:根据深度缓存中的值来判断该片元距离摄像机的距离,当渲染一个片元时,需要把它的深度值和已经存在于深度缓冲中的值进行比较,如果他的之距离摄像机更远,那么说明这个片元不应该被渲染到屏幕上;否则,这个片元应该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中。

    使用深度缓冲,可以让我们不用关心不透明物体的渲染顺序,即使我们先渲染A再渲染B也不用担心B会遮盖掉A,因为再进行深度测试时会判断出B距离摄像机更远,也就不会写入到颜色缓冲中。但如果想要实现透明效果,我们就会关闭深度写入。

    透明度测试:它采用一种“霸道极端”的机制,只要一个片元的透明度不满足条件,那么他对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则就会按照普通的不透明物体的处理方式来处理它,即进行深度测试,深度写入等。也就是说,透明度测试是不需要关闭深度写入的,它和其他不透明物体最大的不同就是他会根据透明度来舍弃一些片元,虽然简单,但是它产生的效果也很极端,要么完全透明,要么完全不透明。

    透明度混合:这种方法可以得到真正的半透明效果。他会使用当前片元的透明度作为混合因子,与已经存储再颜色缓冲中的颜色进行混合,得到新的颜色。但是,透明度混合需要关闭深度写入,这使得我们要非常小心物体的渲染顺序。需要注意的是,透明度混合之关闭了深度写入,但没有关闭深度测试,意味着,当使用透明度混合渲染一个片元时,还是会比较它的深度值与当前深度缓冲中的深度值,如果他的深度值距离摄像机更远,那么就不会再次进行深度混合操作。这一点决定了,当一个不透明物体出现在一个透明物体前,我们先渲染了不透明物体,它依然可以正常地遮挡住透明物体。也就是说,对于透明度混合来说,深度缓冲是只读的。

    为什么渲染顺序很重要

    对于透明混合技术,需要关闭深度写入,此时我们就要小心处理透明物体的渲染。

    为什么要关闭深度写入呢?如果不关闭深度写入,一个半透明表明背后的表面本来是可以透过它被我们看到的,但是由于深度测试时判断结果是该半透明表面距离摄像机更近,导致后面的表面将会被剔除,我们也就无法透过半透明表面看到后面的物体了。但是,我们由此破环了深度缓冲的工作机制。

    不同的渲染顺序会有什么结果呢。

    我们先渲染B再渲染A,那么由于不透明物体开启了深度测试和深度检验,此时深度缓冲中没有任何有效数据,因此B会首先写入颜色缓冲和深度缓冲。随后我们渲染A,透明物体仍然会进行深度测试,因此我们会发现和B相比A距离摄像机更近,我们会使用A的透明度来和颜色缓冲中的B的颜色进行混合,得到正确的半透明效果。

    如果我们先渲染A再渲染B。渲染A时,深度缓冲中没有任何有效数据,因此A直接写入颜色缓冲中,但由于对半透明物体关闭了深度写入,此时A不会修改深度缓冲。等到渲染B时,B会进行深度测试,发现,深度测试中还没有数据那B就写入到颜色缓冲中了,结果B就会覆盖A的颜色。从视觉上B就出现在了A的前面就错误了。

     

    我们还是考虑不同的渲染顺序有什么不同的结果。

    第一种,先渲染B再渲染A。那么B会正常写入颜色缓冲,然后会和颜色缓冲中的B颜色进行混合,得到半透明的效果。

    第二种情况,我们先渲染A再渲染B。那么A会先写入颜色缓冲,随后B会和颜色缓冲中的A进行混合,这样混合后的结果会反过来,看起来B就在A的前面,得到错误的半透明结果。

    基于这两点,渲染引擎一般都会先对物体进行排序,再渲染。常用的方法是。

    1. 先渲染所有不透明的物体,并开启他们的深度测试和深度写入。
    2. 把半透明物体按照他们距离摄像机的远近进行排序,然后按照从后往前的顺序渲染这些半透明物体,并开启他们的深度测试,但关闭深度写入。

    Unity自定义的五个渲染队列

    透明度测试

    从图中可以看到,透明测试得到的透明效果很极端,要么完全透明,要么完全不透明,他的效果往往像是在不透明物体上挖一个空洞。而且得到的透明效果在边缘处往往参差不起有锯齿,因为在边界纹理的透明度的变化精度问题。为了得到更加柔滑的透明效果,就可以使用透明度混合。

    代码

    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
    	}
    	SubShader {
    		Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    		
    		Pass {
    			Tags { "LightMode"="ForwardBase" }
    			
    			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;
    			};
    			
    			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;
    			}
    			
    			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);
    			}
    			
    			ENDCG
    		}
    	} 
    	FallBack "Transparent/Cutout/VertexLit"
    }
    

    透明度混合

    透明度混合的实现要比透明度测试复杂一些,这是因为我们在处理透明度测试时,实际上跟对待普通不透明的物体几乎是一样的,只是在片元着色器中增加了对透明度判断并裁剪片元的代码。

    透明度混合:这种方法可以真正的得到半透明的效果。它会使用当前片元的透明度作为混合因子,与已经存储颜色缓冲的颜色进行混合,得到新的颜色,但是透明度很合需要关闭深度写入这使得我们要非常小心物体的渲染顺序。

    为了进行很合,我们需要使用Unity提供混合命令——Blend。Blend是unity提供的设置混合模式的命令。想要实现半透明的效果就需要把当前自身色颜色和已经存在于颜色缓冲中的颜色进行混合,混合时使用的函数就是由该命令决定的。

     

    代码 

    Shader "Unity Shaders Book/Chapter 8/Alpha Blend" {
    	Properties {
    		_Color ("Color Tint", Color) = (1, 1, 1, 1)
    		_MainTex ("Main Tex", 2D) = "white" {}
    		_AlphaScale ("Alpha Scale", Range(0, 1)) = 1
    	}
    	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 "Lighting.cginc"
    			
    			fixed4 _Color;
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			fixed _AlphaScale;
    			
    			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;
    			};
    			
    			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;
    			}
    			
    			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.xyz * albedo;
    				
    				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
    				
    				return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
    			}
    			
    			ENDCG
    		}
    	} 
    	FallBack "Transparent/VertexLit"
    }
    

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

    使用两个Pass来渲染模型:第一个pass开启深度写入,但不输出颜色,他的目的仅仅是为了把模型深度值写入深度缓冲中;第二个pass进行正常的透明度混合,由于上一个pass已经按照像素级别的深度排序结果进行透明渲染。但这种方法的缺点在于,多使用一个pass会对性能造成一定的影响。

    这个新添加的Pass的目的仅仅是为了把模型的深度信息写入深度缓冲中,从而剔除模型中被自身遮挡的片元。因此,在pass的第一行开启了深度写入。在第二行,我们使用一个新的渲染命令——ColorMask。在ShaderLab中,ColorMask用于设置颜色通道的写掩码。

    当ColorMask为0时,意味着该Pass不写入任何颜色通道,即不会输出任何颜色。这正是我们需要的——该pass只需要写入深度缓存即可。

    代码 

    Shader "Unity Shaders Book/Chapter 8/Alpha Blending With ZWrite" {
    	Properties {
    		_Color ("Color Tint", Color) = (1, 1, 1, 1)
    		_MainTex ("Main Tex", 2D) = "white" {}
    		_AlphaScale ("Alpha Scale", Range(0, 1)) = 1
    	}
    	SubShader {
    		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
    		
    		// Extra pass that renders to depth buffer only
    		Pass {
    			ZWrite On
    			ColorMask 0
    		}
    		
    		Pass {
    			Tags { "LightMode"="ForwardBase" }
    			
    			ZWrite Off
    			Blend SrcAlpha OneMinusSrcAlpha
    			
    			CGPROGRAM
    			
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "Lighting.cginc"
    			
    			fixed4 _Color;
    			sampler2D _MainTex;
    			float4 _MainTex_ST;
    			fixed _AlphaScale;
    			
    			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;
    			};
    			
    			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;
    			}
    			
    			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.xyz * albedo;
    				
    				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
    				
    				return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
    			}
    			
    			ENDCG
    		}
    	} 
    	FallBack "Transparent/VertexLit"
    }
    

    ShaderLab的混合命令

    混合还有很多其他的用处,不仅仅是用于透明度的混合。当片元着色器产生一个颜色的时候,可以选择与颜色缓存中的颜色进行混合。这样一来混合就和两个操作数有关:源颜色和目标颜色。源颜色我们可用S表示,指的是由片元着色器产生的颜色值:目标颜色我们用D表示,指的是从颜色缓存中读取到的颜色值。对对他们进行混合后得到的输出颜色,我们用O来表示,他会重新写入到颜色缓存中,需要注意的是,当我们谈及混合中的源颜色目标颜色和输出颜色时,他们都包含了RGBA四个通道的值,而并非仅仅是RGB通道。

    想要使用混合,我们必须开启它。在Unity中,当我们使用Blend命令时,除了设置混合状态以外也开启了混合。但是,在其他图形api中我们是需要手动开启的。

     

     混合操作

     

    常见的混合类型

    通过混合操作和混合因子命令的组合,我们可以得到一些类似Photoshop混合模式中的混合效果:

    //正常,即透明度混合

    Blend SrcAlpha OneMinusSrcAlpha

    //柔和相加

    Blend OneMinnusDstColor One

    //正片叠低,即相乘

    Blend DstColor Zero

    //两倍相乘

    Blend DstColor SrcColor

    //变暗

    BlendOp Min

    Blend One One

    //变亮

    BlendOp Max

    Blend One One

    //滤色

    Blend OneMinusDstColor One

    //等同于

    Blend One OneMinusSrcColor

    //线性减淡

    Blend One One

    双面渲染的透明效果

    虽然上面使用Min和Max混合操作时仍然设置了混合因子,但实际上他们并不会对结果有任何影响,因为Min和Max混合操作回忽略混合因子。另一点是,虽然上面有混合模式并没有设置混合操作的种类,但是他们默认就是使用加法操作,相当于设置了BlendOpAdd。

    在显示生活中,如果一个物体是透明的,意味着我们不但能透过她看到其他物体还能看到她的内部结构。在前面无论是透明度测试还是透明度混合,我们都没有办法观察到正方形内部以及背面的形状,导致物体看起来就像是只有半个一样。这是因为默认情况下渲染引擎剔除了物体背面的渲染图元,只渲染物体的正面。如果我们想要得到双面的渲染效果,我们可以使用Cull命令来控制需要剔除那个面的渲染图元。

    Cull Back Front Off

    如果设置为Back,那么那些背对摄像机的渲染图元就不会被渲染,这也是默认情况下的剔除状态:如果设置为Front,那么那些朝向摄像机的渲染图元就不会被渲染:如果设置为Off,就会关闭剔除功能,那么所有的渲染图元都会被渲染,但由于这时需要渲染的图元数目会成倍增加,因此除非是特殊效果,例如这里的双面渲染的透明效果,通常情况是不会关闭剔除功能的。

    代码 

    Shader "Unity Shaders Book/Chapter 8/Alpha Test With Both Side" {
    	Properties {
    		_Color ("Color Tint", Color) = (1, 1, 1, 1)
    		_MainTex ("Main Tex", 2D) = "white" {}
    		_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
    	}
    	SubShader {
    		Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    		
    		Pass {
    			Tags { "LightMode"="ForwardBase" }
    			
    			// Turn off culling
    			Cull Off
    			
    			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;
    			};
    			
    			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;
    			}
    			
    			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.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
    				
    				return fixed4(ambient + diffuse, 1.0);
    			}
    			
    			ENDCG
    		}
    	} 
    	FallBack "Transparent/Cutout/VertexLit"
    }
    

    展开全文
  • Unity Shader 透明效果

    2021-03-24 10:29:52
    透明度为1时,表示该像素是完全不透明的,而当其为0时,则该像素完全不会显示。 一、基本方法 Unity实现透明效果,通常有两种方法: 透明度测试,它的机制是简单粗暴的。只要一个片元的透明度不满足条件(通常指...

    透明效果

    导言

    每个片元除了颜色值和深度值之外,它还有一个透明度属性。当透明度为1时,表示该像素是完全不透明的,而当其为0时,则该像素完全不会显示。

    一、基本方法

    Unity实现透明效果,通常有两种方法:

    1. 透明度测试,它的机制是简单粗暴的。只要一个片元的透明度不满足条件(通常指小于某个阈值),那么它对应的片元就不会再进行任何处理,也不会对颜色缓存产生影响。否则,就会按照普通的不透明物体的处理方式来处理它。这种方式无法得到半透明效果。
    2. 透明度混合,这种方法可以得到半透明的效果。它使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的值进行混合,得到新的颜色。但是需要关闭深度写入。

    深度缓冲与渲染顺序

    对于不透明物体,引擎其实不需要考虑物体的渲染的先后顺序,原因就是深度缓冲(depth buffer/ z-buffer)的存在。深度缓冲保存了片元距离摄像机的距离。基本思想是,当渲染一个片元时,需要将它的深度和深度缓冲中的值进行比较(1)。如果它的值距离摄像机更远,那么说明这个片元被之前渲染的物体遮挡了,不需要进行渲染。如果它的值更近,这个片元应该覆盖掉原颜色缓冲中的颜色值,同时更新深度值(2)

    • 下划线(1)这一步操作,称为深度测试。
    • 下划线(2)这一步操作,称为深度写入。

    我们细细想想,透明度混合其实是开启了深度测试,但是关闭了深度写入。因为当我们要渲染一个透明物体,它挡住了一个已经渲染的不透明物体。事实上我们还是可以透过去看到不透明物体,因此不能更新深度缓冲。但是如果我们要渲染的透明物体,在不透明物体之后,通过深度测试,我们就知道不需要渲染这个透明物体了。

    二、Unity Shader的渲染顺序

    Unity提供了渲染队列这一解决方案,使用SubShader的Queue标签来决定我们的模型将归于哪个渲染队列。

    在这里插入图片描述

    三、Unity shader中实现透明度测试的方法

    在片元着色器上加上这一句,代表小于_Cutoff会舍弃该片元的输出,也就是产生完全透明的效果。

     clip(textColor.a - _Cutoff); 
    

    在对应场景中调节材质面板的Alpha Cutoff 数值,可以看到不通透明度的区域从不透明到透明的突变。

    在这里插入图片描述

    总结:

    • 透明度测试只能得到,要么完全透明,要么完全不透明的极端效果;
    • 得到的透明效果在边缘处往往参差不齐,有锯齿,如上图;这是由于在边界处纹理透明度变化精度问题。
    展开全文
  • 可以控制的透明shader

    2015-07-12 21:24:02
    可以控制透明度的shader,方便实用,谢谢大家
  • 一个项目,做世界地图时,希望未开启的地块是线稿,新地块开启时,做一个上色处理。 想到的方案就是:上了色的彩图盖在线稿上,...然后用mask不同的颜色来区分不同的色块,控制是否需要显示。 涉及到 颜色的位操作。
  • unityshader 透明效果:透明度测试、透明度混合、开启深度缓存的透明度混合,双面渲染

            实现透明效果的方法:1.透明度测试2.透明度混合

            深度缓冲Z-buffer决定了哪个物体的那些部分会被渲染在前面,而哪些部分会被遮挡(比较距照相机的距离),渲染一个片元时需要把他的深度值与已经存在在深度缓冲中的值进行比较,判断并将深度值更新到深度缓冲中(如果开启深度写入)。

    透明度测试:某个片元的透明度不满足条件(小于某个值),将直接被舍弃;否则就按不透明物体的方式进行处理,进行深度测试深度写入等,即透明度测试不需要关闭深度写入,效果极端全或无。

    透明度混合:实现真正的半透明效果,使用当前偏远的透明度作为因子与已经在颜色缓冲中的颜色值混合,得到新的颜色,需要关闭深度写入,但没有关闭深度测试,如果深度值距摄像机更远,则不进行混合操作。

    关闭深度写入后,渲染顺序将影响渲染结果。

    解决渲染顺序:渲染队列(subshader中的queue标签)

    Background:1000 在所有队列之前渲染,用于绘制背景物体

    Geometry:2000 默认渲染队列,大多数物体,不透明物体

    AlphaTest:2450 需要透明度测试的物体

    Transparent:3000  在所有geometry和alphatest渲染后,再从后往前的顺序渲染,使用了透明度混合的物体

    Overlay:用于实现叠加效果

    SubShader{
        Tags{"Queue"="AlphaTest"}
        Pass{
            ...
        }
    }

    透明度测试

            透明度测试通常使用clip函数:void clip(floatn x);如果给定的参数任何一个分量是负数,就会舍弃当前像素输出颜色。

            在下面的片元着色器中,使用clip函数,将小于给定值(cutoff)的texcolor不显示。

    
    			
    			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);
    			}
    			
    

     透明度混合

            使用混合命令Blend,设置混合因子,片元源颜色将乘SrcFactor,目标颜色(已经存在于颜色缓冲中的颜色)将乘以DstFactor,再把两者相加存入颜色缓冲。

    DstColor(new)=SrcFactor X SrcColor+DstFactor X DstColor(old)

    需要调整的设置

    更新后的片元着色器,就是在最后输出的透明度上做了变动

     

    关闭深度写入在处理模型本身有复杂的遮挡关系或者包含了非凸网格是会因为排序错误产生错误的效果。 

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

     一种解决方法是使用两个Pass来渲染模型,一个开启深度写入但不输出颜色,仅仅是为了将模型的深度值存入深度缓存中,剔除模型中被自身遮挡的片元,第二个pass进行正常的透明度混合。

    此处ColorMask在ShaderLab中用于设置颜色通道的写掩码, 当其设为0时,表示该Pass不写入任何颜色通道。

    ShaderLab的混合命令

            片元着色器产生一个颜色时,可以选择与颜色缓存中的颜色进行混合,这样这个操作与两个操作数有关:源颜色(S表示片元着色器产生的颜色),目标颜色(D表示从颜色缓冲中读到的颜色),得到的输出颜色记O,都包含RGBA四个通道。

            想要得到O需要两个混合等式,分别计算RGB通道和A通道的混合。如果给出两个因子就用同样的因子计算RGB和A的混合等式,如果给出四个混合因子就用其分别计算RGB和A。

            上面使用的是正常的透明度混合,一些其他的混合操作和混合因子的命令可以实现变暗变量,类似彩铅画风等。见书P175.

            

    双面渲染的透明效果

     透明物体的内部结构在上面的透明度测试与透明度混合中无法看到,因为默认情况下渲染引擎剔除了物体背面(相对于摄像机的方向)的图元,即只有证明,要得到双面效果,就需要通过

    Cull指令来控制需要剔除哪个面。

    Cull Back|Front|Off    默认为back 当关闭off时即可双面。

    透明度测试的双面渲染

    只需在透明度测试的基础上加上cull off即可。

     

     透明度混合的双面渲染

    由于透明度测试关闭了深度写入,需要严格控制渲染顺序从后往前,为了保证正面背面正确渲染,将双面渲染氛围两个pass一个只渲染正面,一个只渲染背面,渲染的方式和之前透明度混合的相同。

    即在一个pass中声明Cull Front,在另一个中声明Cull Back

    效果展示。 

    上述所有的效果汇总:

     

    展开全文
  • ShaderGraph材质透明边框

    千次阅读 2020-03-22 20:39:17
    ShaderGraph材质用于粒子系统同时出现多个同一材质,且有边缘是透明的时。会大概率出现透明边框遮挡其他材质效果的情况。在材质的SurfaceType选择Transparent后取消DepthWrite单选项。之后就不存在透明的边框了上诉...
  • unityshader透明材质处理
  • 为了给纯色模型或是带其他底纹的材质表面添加带alpha通道的透明贴图使用以下方式可实现。这个位置是为了添加纯色和控制颜色强度使用的节点。edge1默认值0.88。这个节点是为了防止颜色溢出添加的。edge2默认值0.9。.....
  • UnityShader入门精要——透明物体阴影

    千次阅读 2022-03-15 12:22:32
    透明度测试: Shader "Unity Shaders Book/Chapter 9/Alpha Test With Shadow" { Properties { _Color ("Color Tint", Color) = (1, 1, 1, 1) _MainTex ("Main Tex", 2D) = "white" {} _Cutoff ("Alpha Cut...
  • EasyAR 显示阴影Shader

    2019-01-24 11:15:04
    EasyAR在透明物体上 显示阴影Shader 文章链接:https://blog.csdn.net/qq_39097425/article/details/86623218
  • 怎么把一张贴图变成透明的 这个透明是有自身纹理凹凸的 不显示颜色 像水的纹理的但是有部分是消失不见的只有结构纹理存在 我知道这个类似法线 但是怎么才能让法线凸出的显示 不突出的不显示
  • Unity透明物体上显示阴影的shader

    千次阅读 2019-05-10 13:54:46
    把这个代码给材质球,材质球给透明物体就行。 不多说上代码 // Upgrade NOTE: replaced ‘mul(UNITY_MATRIX_MVP,)’ with 'UnityObjectToClipPos()’ Shader “GreenArch/Transparent Plane Shadow2” { SubShader {...
  • unity3d:UI shader区域mask透明

    千次阅读 2021-10-12 02:05:29
    1.原始图 2.mask图可分为24个区域,...Shader "UI/MaskAreaAlpha" { Properties { _MainTex("Texture", 2D) = "white" {} _Mask("遮罩", 2D) = "white" {} _Area("区域",Int) = 0 _Color("Tint", Color) =
  • Shader "Custom/s1" { Properties { //变量名("显示在面板上的名字",数据类型) = (值) _Color("我是颜色呀!",Color) = (1,1,1,1) _Ambient("我是环境光",Color) = (0.3,0.3,0.3,0.3) _Specular("反射高光",...
  • 透明度测试:它采用一种“霸道极端”的机制,只要一个片元的透明度不满足条件(通常是小于某个阈值),那么它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就会...
  • Unity Shader透明遮罩效果

    千次阅读 2019-12-17 10:40:06
    透明遮罩位于被遮住物体(图中红色)和显示物体(绿色和白色)前面,优先渲染遮罩,第一个Pass记录透明遮罩的深度之后在绘制透明颜色,这样到绘制被遮住物体时,只要开启ZTest就可以使其深度测试失败,透明遮罩罩住...
  • 可以用双面shader解决。发现一个比较好用的,转载码一下。原地址:https://blog.csdn.net/liang_704959721/article/details/88681768 shader代码如下: Shader "yh/DoubleSide" { Properties { _...
  • Shader笔记六 透明效果

    千次阅读 2018-06-10 11:15:56
    Unity中使用两种方法实现透明效果:透明度测试(Alpha Test)透明度混合(Alpha Blending)开启透明混合后,当一个物体被渲染到屏幕上时,每个片元除了颜色和深度值之外,还具有透明度的属性。透明度为1时,完全不透明,...
  • 屏幕可视范围跟随目标物体移动,可修改可视范围大小,边缘渐变大小、以及遮罩颜色,支持最高物体数量可在Shader中修改,当前版本支持最多9个物体。 效果图如下: 控制面板如下: Shader代码如下: Shader "Peter/...
  • 这是一个着色器,用于显示具有透明度(Alpha通道)的视频,例如WebM。 演示版 浏览器安装 通过在框架后声明此进行安装 <head> <title>My Scene</title> [removed][removed] [removed][removed]...
  • 1.记录找到的一个模型描边中间透明shader,大概就是下图Cube这样. 2.脚本 Shader "Unlit/Shaer" { Properties{ _Color("Main Tint", Color) = (1, 1, 1, 1) _MainTex("Texture", 2D) = "white" {} _...
  • Unity Shader透明效果

    千次阅读 2018-09-17 12:39:47
    透明度为1,则完全不透明,透明度为0,则完全不会显示。 在Unity中我们有两种方式实现透明度效果 透明度测试(Alpha Test):这种方式无法得到真正的半透明效果。只是0或1(完全透明和完全不透明) 透明度混合...
  • shader-透明度测试

    2020-09-07 14:21:55
    小于0的片元剔除,大于0的显示。 实现 Shader "Custom/AlphaTest" { Properties{ _Color("MainTint", Color) = (1,1,1,1) _MainTex("MainTex", 2D) = "white" {} _Cutoff("Alpha Cutoff", Range(0,1)) =
  • 在现实生活中,如果一-个物体是透明的,意味着我们不仅可以透过它看到其他物体的样子,也可以看到它内部的结构。但在前面实现的透明效果中,无论是透明度测试还是透明度混合,我们都无法观察到正方体内部及其背面的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,185
精华内容 4,074
关键字:

shader显示透明