zoukankan      html  css  js  c++  java
  • (六)透明度问题简析

    1.前言

    曾经做过一个项目,要求一个实体模型能够半透明显示,并高亮其中的某一部分。采用unity标准(standard)材质,通过将RenderMode改为transparent,然后通过MeshRender组件更改颜色透明通道进行实现。但是结果不尽人意,这是由于模型之间交互覆盖。很难周全,再次对Unity混合问题进行简析。

    2.渲染队列

    Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="TransparentCutout"}
    

    渲染队列,表示那部分先渲染,并非完全按照深度值来进行。在同一个渲染队列的对象会按深度进行渲染,关闭深度写入的,则按游戏对象位置来处理。
    Background:顾名思义,表示背景队列,此渲染队列的物体最先被渲染。
    Geometry:表示正常的结合对象,在Backgroud队列后被渲染。
    AlphaTest:透明度测试,通过clip可以对color的alpha值进行处理,当大于某一值时就discard掉(可以关闭深度写入ZWrite Off)。
    Transparent:表示半透明队列,此队列的对象一般都是需要进行半透明处理,并关闭深度写入。并且为了保证叠加效果,其在Geometry和AlphaTest之后渲染。半透明处理时要开启混合,即Blend SrcAlpha OneMinusSrcAlpha,关闭混合则为Blend Off。
    Overlay:跟Backgound一样,顾名思义,是最后覆盖之意,表示最后被渲染的一层。

    3.透明度混合

    上文中在Transparent中简单说明透明度混合的关闭开启,再次详细说明一下。混合的意思为上一次buffer中颜色与新计算出来的颜色是否叠加或者覆盖的意思。

    3.1 Blend命令格式

    基本格式为Blend+参数:

    Blend参数形式含义
    Off 关闭混合
    factorA factorB 表示Blend后面加两个参数,以空格分开,将源颜色成以factorA与目标颜色成以factorB相加结果存入颜色缓冲区
    factorA factorB alphaA alphaB 表示Blend后面加四个参数,以空格分开将源颜色成以factorA与目标颜色成以factorB相加结果存入颜色缓冲区,但是混合通道用后两个参数来叠加

    如Blend SrcAlpha OneMinusSrcAlpha。其中SrcAlpha为factorA,OneMinusSrcAlpha为factorB。
    factorA,factorB以及alphaA值如下所示。

    3.2 Blend参数释义

    Blend参数意义
    One/Zero 1/0
    SrcColor/DstColor 源颜色值/目标颜色值
    SrcAlpha/DstAlpha 源颜色透明通道值/目标颜色值透明通道值
    OneMinusSrcAlpha/OneMinusDstAlpha 1-源颜色透明通道值/1-目标颜色值透明通道值
    OneMinusSrcColor/OneMinusDstColor 1-源颜色值/1-源颜色值

    如Blend SrcAlpha OneMinusSrcAlpha表示用源颜色的透明通道值乘以源颜色+目标颜色值乘以(1-源颜色透明通道值)。

    3.3 Blend混合方式

    上述所说的混合方式均为相加方式,是默认方式,也可以通过BlendOp命令更改为相减或者其他。如下所示:
    BlendOp Sub//相减
    Blend One One

    还有RevSub,Min,Max等。

    4.实例分析

    4.1 透明度测试

    透明度测试用于根据透明程度决定是否剔除此像素(也可以在不透明渲染时采用某一颜色值去处理)。此时要开启透明度测试,否则用像素alpha进行判断无效。如下所示,下述代码关闭了剔除功能,如果不需要看到物体内部,可以开启剔除,只渲染一面。

    Shader "LL/AlphaTest"
    {
    	Properties
    	{
    		_MainTex("Main Texture",2D)="white"{}
    		//_DissolveTex("Dissolve Cutoff",2D)="white"{}
    		_Cutoff("Dissolve Cutoff",Range(0,1))=1
    	}
    
    	SubShader
    	{
    		Tags {"Queue"="AlphaTest" "IgnoreProjector"="true" "RenderType"="TransparentCutout"}
    
    		pass
    		{			
    			Tags {"LightMode"="ForwardBase"}
    			Cull off
    	
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    
    			#include "UnityCG.cginc"
    
    			sampler2D _MainTex;
    			//sampler2D _DissolveTex;
    			float _Cutoff;
    
    			struct a2v
    			{
    				float4 vertex:POSITION;
    				float2 uv:TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv:TEXCOORD0;
    				float4 vertex:SV_POSITION;
    			};
    
    			v2f vert(a2v v)
    			{
    				v2f f;
    				f.uv=v.uv;
    				f.vertex=UnityObjectToClipPos(v.vertex);
    				return f;
    			}
    
    			float4 frag(v2f f):SV_TARGET
    			{
    				float4 mainTexColor=tex2D(_MainTex,f.uv);
    				clip(mainTexColor.a-_Cutoff);
    
    				//return float4(mainTexColor.rgb,mainTexColor.a * _Cutoff);
    				return mainTexColor;
    			}
    
    			ENDCG
    		}
    	}
    }
    
    

    4.2 透明度混合

    如果想通过更改alpha值更改模型透明度,则需要开启透明度混合。此时要关闭深度写入,如果需要深度值,可以在其他pass中开启深度写入,但不输出任何颜色值。

    Shader "LL/AlphaBlend"
    {
    	Properties
    	{
    		_MainTex("Main Texture",2D)="white"{}
    		//_DissolveTex("Dissolve Cutoff",2D)="white"{}
    		_Cutoff("Dissolve Cutoff",Range(0,1))=1
    	}
    
    	SubShader
    	{
    		Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="TransparentCutout"}
    
    		// pass
    		// {
    		// 	Tags {"LightMode" = "ForwardBase"}
    		// 	Cull Front
    		// 	ZWrite On
    		// 	ColorMask 0
    		// }
    		pass
    		{			
    			Tags {"LightMode"="ForwardBase"}
    			//Cull Back
    			//Cull Off
    			ZWrite Off
    			Blend SrcAlpha OneMinusSrcAlpha
    
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    
    			#include "UnityCG.cginc"
    
    			sampler2D _MainTex;
    			//sampler2D _DissolveTex;
    			float _Cutoff;
    
    			struct a2v
    			{
    				float4 vertex:POSITION;
    				float2 uv:TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv:TEXCOORD0;
    				float4 vertex:SV_POSITION;
    			};
    
    			v2f vert(a2v v)
    			{
    				v2f f;
    				f.uv=v.uv;
    				f.vertex=UnityObjectToClipPos(v.vertex);
    				return f;
    			}
    
    			float4 frag(v2f f):SV_TARGET
    			{
    				float4 mainTexColor=tex2D(_MainTex,f.uv);
    				return float4(mainTexColor.rgb,mainTexColor.a * _Cutoff);
    			}
    
    			ENDCG
    		}
    	}
    }
    

    4.3 透明度混合+双面渲染

    双面渲染可以在上述shader中直接Cull Off来实现,但是会看着不是很自然(如果不对比下述代码的效果时看不出来的),所以一般是先剔除正面,结束后再剔除背面。

    Shader "LL/AlphaBlendTwoSides"
    {
    	Properties
    	{
    		_MainTex("Main Texture",2D)="white"{}
    		//_DissolveTex("Dissolve Cutoff",2D)="white"{}
    		_Cutoff("Dissolve Cutoff",Range(0,1))=1
    	}
    
    	SubShader
    	{
    		Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="TransparentCutout"}
    
    		// pass
    		// {
    		// 	Tags {"LightMode" = "ForwardBase"}
    		// 	Cull Front
    		// 	ZWrite On
    		// 	ColorMask 0
    		// }
    		pass
    		{			
    			Tags {"LightMode"="ForwardBase"}
    			Cull Front
    			//Cull Off
    			ZWrite Off
    			Blend SrcAlpha OneMinusSrcAlpha
    
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    
    			#include "UnityCG.cginc"
    
    			sampler2D _MainTex;
    			//sampler2D _DissolveTex;
    			float _Cutoff;
    
    			struct a2v
    			{
    				float4 vertex:POSITION;
    				float2 uv:TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv:TEXCOORD0;
    				float4 vertex:SV_POSITION;
    			};
    
    			v2f vert(a2v v)
    			{
    				v2f f;
    				f.uv=v.uv;
    				f.vertex=UnityObjectToClipPos(v.vertex);
    				return f;
    			}
    
    			float4 frag(v2f f):SV_TARGET
    			{
    				float4 mainTexColor=tex2D(_MainTex,f.uv);
    				return float4(mainTexColor.rgb,mainTexColor.a * _Cutoff);
    			}
    
    			ENDCG
    		}
    
    		pass
    		{			
    			Tags {"LightMode"="ForwardBase"}
    			Cull Back
    			//Cull Off
    			ZWrite Off
    			Blend SrcAlpha OneMinusSrcAlpha
    
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    
    			#include "UnityCG.cginc"
    
    			sampler2D _MainTex;
    			//sampler2D _DissolveTex;
    			float _Cutoff;
    
    			struct a2v
    			{
    				float4 vertex:POSITION;
    				float2 uv:TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv:TEXCOORD0;
    				float4 vertex:SV_POSITION;
    			};
    
    			v2f vert(a2v v)
    			{
    				v2f f;
    				f.uv=v.uv;
    				f.vertex=UnityObjectToClipPos(v.vertex);
    				return f;
    			}
    
    			float4 frag(v2f f):SV_TARGET
    			{
    				float4 mainTexColor=tex2D(_MainTex,f.uv);
    				return float4(mainTexColor.rgb,mainTexColor.a * _Cutoff);
    			}
    
    			ENDCG
    		}
    	}
    }
    

    5.结语

    半透明问题比较复杂,但实际操作起来却没有那么繁杂。

  • 相关阅读:
    [Everyday Mathematics]20150226
    [Everyday Mathematics]20150225
    [Everyday Mathematics]20150224
    [Everyday Mathematics]20150223
    [Everyday Mathematics]20150222
    [Everyday Mathematics]20150221
    [Everyday Mathematics]20150220
    [Everyday Mathematics]20150219
    [Everyday Mathematics]20150218
    [Everyday Mathematic]20150217
  • 原文地址:https://www.cnblogs.com/llstart-new0201/p/11975807.html
Copyright © 2011-2022 走看看