700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > unity shader学习---透明度测试 透明度混合

unity shader学习---透明度测试 透明度混合

时间:2019-07-09 00:39:38

相关推荐

unity shader学习---透明度测试 透明度混合

unity实现透明效果

效果图理论Alpha TestAlpha Blend改进开启深度写入的半透明效果双面渲染的透明效果 代码部分

效果图

Alpha Test

Alpha Test With Both Side:Cull Off关闭剔除

Alpha Blend Scale = 0.5

AlphaBlendZWrite:新加一个Pass,Zwrite On, 按照像素级别的深度排序结果进行透明渲染

Alpha Blend With Both Side:两个Pass,Cull Front Cull Back

理论

渲染不透明和半透明物体

景中既有不透明物体,又有半透明物体时,渲染引擎一般都会先对物体进行排序,再渲染

(1) 先渲染所有不透明物体,开启它们的深度测试和深度写入,渲染顺序为从前往后(Front-to-Back)

(2) 再渲染半透明物体,开启它们的深度测试,但关闭深度写入,按它们距离摄像机的远近进行排序,渲染顺序为从后往前(Back-to-Front)

【渲染不透明物体】

不考虑渲染顺序也能得到正确的排序效果,利用深度缓冲(z-buffer)解决可见性问题。

当渲染每个片元时, 需要把它的深度值和已经存在于深度缓冲中的值进行比较(如果开启了深度测试),如果它的值距离摄像机更远,那么说明这个片元不应该被渲染到屏幕上(有物体挡住了它);否则,这个片元应该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中(如果开启了深度写入)

为什么从前往后渲染?

减少深度颜色缓冲器的写入操作,提升性能,避免overdraw

【渲染透明物体】

通过控制透明通道 (Alpha Channel) 实现透明效果

1、透明度测试:

不需要关闭深度测试和深度写入

产生的效果很极端,要么完全透明,即看不到,要么完全不透明,就像不透明物体那样。只要片元的透明度不满足条件(通常是小千某个阙值),那么就会被舍弃。否则,就会按照普通的不透明物体的处理方式来处理它,即进行深度测试、深度写入等。

2、透明度混合:

开启深度测试,关闭深度写入(深度缓冲是只读的)

得到真正的半透明效果,使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。

为什么要关闭深度写入?

如果不关闭深度写入,半透物体后面的表面将会被剔除,就无法透过半透明表面看到后面的物体了

为什么要非常小心物体的渲染顺序?

为了渲染的正确性

如何排序?

尽可能让模型是凸面体,并且考虑将复杂的模型拆分成可以独立排序的多个子模型等

unity Shader的渲染顺序

透明度测试

透明度混合

Alpha Test

【效果】

默认剔除背面,在Pass里设置Cull Off关闭剔除

得到的透明效果在边缘处往往参差不齐有锯齿,这是因为在边界处纹理的透明度的变化精度问题

【代码解析】

跟渲染普通的不透明物体几乎是一样的

FS:增加了对透明度判断并裁剪片元

Properties{_Color("Color Tint", Color) = (1, 1, 1, 1) // Diffuse_MainTex("Main Tex", 2D) = "white" {}_Cutoff("Alpha Cutoff", Range(0, 1)) = 0.5 // cutoff}

SubShader{Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"} Pass {Tags {"LightMode" = "ForwardBase" } // 定义了正确的 LigbtMode,才能正确得到一些 Unity的内置光照变量,例如_LigbtColorO

透明度测试的subshader的固定三个标签

“Queue” = “AlphaTest” : 透明度测试使用的渲染队列

“IgnoreProjector” = “True”:这个 Shader 不会受到投影器(Projectors)的影响

“RenderType” = “TransparentCutout”: 该 Shader是个使用了透明度测试的Shader

fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _Cutoff; // 范围在[O,1], 使用 fixed 来存储

和Properties 语义块中声明的属性建立联系

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

VS略,同纹理映射

FS

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

clip CG 中的一个函数

if ((texColor.a - _Cutoff) < 0.0) {

discard;

}

FallBack "Transparent/Cutout/VertexLit"

和之前使用的 Diffuse Specular 不同,能够保证SubShader 无法在当前显卡上工作时有合适的代替 Shader, 还可以保证使用透明度测试的物体可以正确地向其他物体投射阴影

Alpha Blend

alpha scale = 0.3

alpha scale = 0.8

【代码解析】

FS:把当前自身的颜色和已经存在于颜色缓冲中的颜色值进行混合

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"}

使用了透明度混合的 Shader都应该在 SubShader 中设置这3个标签,透明度测试用的是TransparentCutout,透明度混合用的是Transparent

Pass {Tags {"LightMode" = "ForwardBase" } // 正确提供各个光照变量ZWrite Off // 深度只读Blend SrcAlpha OneMinusSrcAlpha //

开启并设置了该Pass的混合模式(重要!!)

将源颜色(该片元着色器产生的颜色)的混合因子设为SrcAlpha, 把目标颜色(已经存在于颜色缓冲中的颜色)的混合因子设为OneMinusSrcAlpha

当设置混合状态时,我们实际上设置的就是混合等式中的操作和因子

混合操作:

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

VS略

FS:

fixed4 texColor = tex2D(_MainTex, i.uv);fixed3 albedo = texColor.rgb * _Color.rgb; // albedofixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));return fixed4(ambient + diffuse, texColor.a * _AlphaScale);

先采样纹理贴图,然后设置该FS返回值中的透明通道 (= 纹理像素的透明通道* AlphaScale )

改进

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

由于关闭深度写入,无法对模型进行像素级别的深度,当模型本身有复杂的遮挡关系或是包含了复杂的非凸网格的时候,就会有各种各样因为排序错误而产生的错误的透明效果

一种解决方法是分割网格

一种解决方法是使用两个Pass来渲染模型,第一个 Pass 开启深度写入,但不输出颜色,它的目的仅仅是为了把该模型的深度值写入深度缓冲中;第二个Pass 进行正常的透明度混合,但是对性能有一定影响

// 新加一个PassPass{Zwrite OnColorMask 0 // }

ColorMask 用于设置颜色通道的写掩码 write mask,0代表 Pass 不写入任何颜色通道,即不会输出任何颜色

效果:

双面渲染的透明效果

默认情况下渲染引擎剔除了物体背面(相对于摄像机的方向)的渲染图元,而只渲染了物体的正面

Cull Back I Front I Off

如果设置为 Off,就会关闭剔除功能,那么所有的渲染图元都会被渲染,计算量成倍增加,因此除非是用于特殊效果,例如这里的双面渲染的透明效果,通常是不会关闭剔除功能的

透明度测试的双面渲染

Cull Off透明度混合的双面渲染

分成两个 Pass——第一个 Pass 渲染背面(Cull Front),第二个 Pass只渲染正面(Cull Back),由于 Unity 会顺序执行 SubShader 中的各个 Pass, 从而可以保证先渲染背面,后渲染正面,渲染关系正确

对比:

代码部分

【alpha test】

Shader "Custom/AlpbaTest"{Properties{_Color("Color Tint", Color) = (1, 1, 1, 1) // Diffuse_MainTex("Main Tex", 2D) = "white" {}_Cutoff("Alpha Cutoff", Range(0, 1)) = 0.5 // cutoff}SubShader{// 透明度测试的subshader的固定三个标签// AlphaTest: 透明度测试使用的渲染队列// TransparentCutout:该 Shader是个使用了透明度测试的Shader// "IgnoreProjector" = "True":这个 Shader 不会受到投影器(Projectors)的影响Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"} Pass {Tags {"LightMode" = "ForwardBase" } // 定义了正确的 LigbtMode,才能正确得到一些 Unity的内置光照变量,例如_LigbtColorOCull Off // 关闭剔除,看到背面CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _Cutoff; // 范围在[O I], 使用 fixed 来存储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 testclip(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"}

【Alpha Blend】

// Q1// 当模型本身有复杂的遮挡关系或是包含了复杂的非凸网格的时候,就会有各种各样因为排序错误而产生的错误的透明效果。// 新加一个 Pass,开启深度写入,但不输出颜色; 第二个Pass 进行正常的透明度混合// 就可以按照像素级别的深度排序结果进行透明渲染,但是对性能有一定的影响// Q2 双面渲染// 第一个 Pass 渲染背面,第二个 Pass只渲染正面// 保证正确的深度渲染关系Shader "Custom/AlphaBlend"{Properties{_Color("Color Tint", Color) = (1, 1, 1, 1)_MainTex("Main Tex", 2D) = "white" {}_AlphaScale("Alpha Scale", Range(0, 1)) = 1 // 控制透明度}SubShader{// 通常,使用了透明度混合的 Shader都应该在 SubShader 中设置这3个标签,透明度测试用的是TransparentCutoutTags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}// 新加一个Pass,按照像素级别的深度排序结果进行透明渲染,但是对性能有一定的影响Pass{Zwrite OnColorMask 0 // ColorMask 用于设置颜色通道的写掩码 write mask,0代表 Pass 不写入任何颜色通道,即不会输出任何颜色}Pass {Tags {"LightMode" = "ForwardBase" } // 正确提供各个光照变量// Cull OffZWrite Off // 深度只读Blend SrcAlpha OneMinusSrcAlpha // 开启并设置了该Pass的混合模式[重要],将源颜色(该片元着色器产生的颜色)的混合因子设为SrcAlpha, 把目标颜色(已经存在于颜色缓冲中的颜色)的混合因子设为OneMinusSrcAlpha// BlendOp MinCGPROGRAM#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; // albedofixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));return fixed4(ambient + diffuse, texColor.a * _AlphaScale); // 纹理像素的透明通道 * _AlphaScale}ENDCG}}FallBack "Transparent/VertexLit"}

【Alpha Blend With Both Side】

Shader "Custom/Alpha Blend With Both Side" {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" }// First pass renders only back faces Cull FrontZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#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}Pass {Tags {"LightMode"="ForwardBase" }// Second pass renders only front faces Cull BackZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#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"}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。