作者:王子饼干 ——镇江虹视游戏科技有限公司联合创始人、《多洛可小镇》制作人
原文链接:UnityShader入门精要-URP管线5. 透明度混合与透明度测试
原文发布时间:2022年6月22日
文章类型: 授权转载
本节中我们回顾一下两种透明方法,透明度混合与透明度测试。透明度混合用于实现半透明,透明度测试则用于实现消融效果之类“消失”效果。
透明度混合是一种混合方式,所谓混合,就是将两种颜色按照一定的公式混合在一起,对于两个重叠的物体A和B来说,如果A的颜色采一点,B的颜色拿一点,两者叠加起来,就是透明度混合。
虽然透明度混合一种算法,但是基本上不用我们自己手动计算,只需要设定好物体的渲染方式与渲染队列,以及设置混合模式就可以了。
在片元着色器中,我们虽然一直要输出一个half4类型的变量,但是其实第四个分量是不起作用的。因为我们设置的渲染类型为Opaque。所以首要的任务是设置渲染标签。
Tags{
"RenderPipeline"="UniversalRenderPipeline"
"RenderType"="Transparent"
"IgnoreProjector"="True"
"Queue"="Transparent"
}
有了以上条件之后,之后设置混合模式就可以了。
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
之后我们可以通过传入一个透明度值来控制透明度。以下是完整的代码
Shader "URPNotes/AlphaBlend"{
Properties{
_BaseColor("Base Color",Color) = (1.0,1.0,1.0,1.0)
_MainTex("Main Texture",2D) = "white"{}
_Alpha("Alpha",Range(0,1)) = 1.0
}
SubShader{
Tags{
/* 设置渲染类型为透明,忽略其他物体的投影,渲染队列为透明度渲染队列,这个
队列会在不透明物体队列之后渲染 */
"RenderType"="Transparent"
"RenderPipeline"="UniversalRenderPipeline"
"IgnoreProjector"="True"
"Queue"="Transparent"
}
pass{
/* 设置混合模式,我们选择的模式是透明度混合,所以使用透明度混合,并关闭ZWrite
之后正常的计算该有的东西就可以了,所有的工作都将由Unity来完成 */
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"
#pragma vertex Vertex
#pragma fragment Pixel
CBUFFER_START(UnityPerMaterial)
half4 _BaseColor;
half _Alpha;
float4 _MainTex_ST;
CBUFFER_END
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
struct vertexInput{
float4 vertex:POSITION;
float2 uv:TEXCOORD0;
};
struct vertexOutput{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
vertexOutput Vertex(vertexInput v){
vertexOutput o;
o.pos = TransformObjectToHClip(v.vertex.xyz);
o.uv = TRANSFORM_TEX(v.uv,_MainTex);
return o;
}
half4 Pixel(vertexOutput i):SV_TARGET{
half3 albeo = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv).xyz * _BaseColor.xyz;
return half4(albeo,_Alpha);
}
ENDHLSL
}
}
}
下面是透明度混合的效果
不过这样渲染出来的效果是没有双面渲染的,也就是透过模型,我们没有办法看见模型的内部。为了解决这个问题,我们可以将模型剔除关闭。
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
之后透过模型就可以看到模型的后面了。
透明度测试就是一种用于剔除透明像素的手段,它严格来说不是透明效果。而且把一部分像素挖掉。(也可以理解为把这部分像素的透明度设置为0),它本身还是不透明的,而且整个效果只依赖一个叫做clip的函数。
clip(value) //把值低于value的像素挖掉
一般,我们可以将value设置为,这样就可以剔除alpha值低于threshold的像素了。除了这个函数的使用,复制一个基础的着色器过来就可以了。下面是全部的代码。
Shader "URPNotes/AlphaTest"{
Properties{
_BaseColor("Base Color",Color) = (1.0,1.0,1.0,1.0)
_MainTex("Main Texture",2D) = "white"{}
_AlphaTest("Alpha Threshold",Range(0,1)) = 0
}
SubShader{
Tags{
/*想不到把,透明度测试还是不透明物体*/
"RenderPipeline"="UniversalRenderPipeline"
"RenderType"="Opaque"
}
pass{
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"
#pragma vertex Vertex
#pragma fragment Pixel
CBUFFER_START(UnityPerMaterial)
half4 _BaseColor;
half _AlphaTest;
float4 _MainTex_ST;
CBUFFER_END
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
struct vertexInput{
float4 vertex:POSITION;
float2 uv:TEXCOORD0;
};
struct vertexOutput{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
vertexOutput Vertex(vertexInput v){
vertexOutput o;
o.pos = TransformObjectToHClip(v.vertex.xyz);
o.uv = TRANSFORM_TEX(v.uv,_MainTex);
return o;
}
half4 Pixel(vertexInput i):SV_TARGET{
half4 albedo = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv);
clip(albedo.a - _AlphaTest); //剔除掉透明度值低于_AlphaTest的像素。
return albedo * _BaseColor;
}
ENDHLSL
}
}
}
下面是最终的效果。
带有透明通道的素材绘制到一个四边面上,透明像素还是会绘制出来。所以我们增加一个透明度测试来提出掉透明的像素,只留下不透明的部分。
这里用的是自己画的素材(逃)
该部分比较简单,主要是回顾一下Blend,ZWrite,Cull操作符。
另外,本次使用到的所有代码都已经上传到了我的github,在下面的链接中可以找到。如果你喜欢这个系列的文章,欢迎关注该专栏,或者给我的github贡献一颗⭐,感谢阅读。