- 透明效果
渲染模型时控制它的透明通道(Alpha)
透明度: 1:该像素是完全不透明的。 0:该像素完全不会显示
对于不透明物体,不考虑渲染顺序也能得到正确的排序效果。
方法 | 原理 | 结果 | 条件 | 缺陷 |
---|---|---|---|---|
透明度测试 | 1.只要一个片元的透明度不满足条件,对应的片元就会被舍弃 2.被舍弃的不会进行任何处理,也不会对颜色缓冲产生任何影响 3.按普通的不透明物体的方式处理 | 霸道极端的机制 完全透明或者完全不透明 | 不关闭深度写入 | 效果极端 边缘效果参差不齐,有锯齿 透明度的变换精度导致 |
透明度混合 | 1.当前片元的透明度作为混合因子,与存储的颜色值混合 | 可以得到真正的半透明效果 | 关闭深度写入,不关闭深度测试 |
渲染引擎对物体先排序再渲染
1.先渲染所有不透明物体,并开启它们的深度测试和深度写入。
2.半透明物体按距离摄像机距离排序,从后往前开启深度深度测试,关闭深度写入顺序渲染。
第2步骤若遇交叉就有问题。因此尽可能将复杂的模型拆成独立的多个子模型。
- 透明度测试
/*********************************************************
透明度测试
1.只要一个片元的透明度不满足条件,对应的片元就会舍弃。
2.被舍弃的不会进行任何处理,也不会对颜色缓冲产生影响
3.没有舍弃的按普通不透明物体的处理方式处理
**********************************************************/
Shader"AlphaTest"{
Properties{
_MainTex("Main Tex", 2D) = "white"{}
_CutOff("Cut Off", Range(0,1)) = 0 //剔除的判断条件
_Color("Color Tint",Color)=(1,1,1,1)
}
SubShader{
//队列透明度测试,忽略Projector投影器的影响,shader分组到TransparentCutout
Tags{"Queue" = "AlphaTest" "IngoreProjector"="True" "RenderType"="TransparentCutout"}
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "UnityCG.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float2 uv:TEXCOORD2;
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
half _CutOff;
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(i.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i):SV_Target{
fixed3 wNormal = normalize(i.worldNormal);
fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texcoord = tex2D(_MainTex, i.uv)
clip(texcoord.a - _CutOff); //剔除
fixed3 albedo = texcoord.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wLightdir));
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);
}
ENDCG
}
}
FallBack "Transparent/Cutout/VertexLit"//内置的
//保证使用透明度测试的物体可以正确的向其他物体投射阴影
}
void clip(param) float4 float3…
/// < summary>
/// 如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色
/// < /summary>
/// < param name=""> 裁剪时使用的标量或矢量条件 </ param>
/// void clip(float4 x) if(any(x < 0)) discard // discard:剔除该片元
- 透明度混合
混合命令–Blend
混合操作数 | 定义 | |
---|---|---|
源颜色 | S | 由片元着色器产生的颜色值 |
目标颜色 | D | 从颜色缓冲中读取到的颜色值 |
混合后的颜色 | O | S、D混合后得到输出的颜色 |
语义 | 描述 | 例 | |
---|---|---|---|
Blend Off | 关闭混合 | ||
Blend SrcFactor DstFactor | 开启混合,并设置混合因子 | 最终 = 源 * SrcFactor + 目标 * DstFactor | Blend SrcAplha OneMinusSrcAlpha 透明度混合 |
Blend SrcFactor DstFactor, ScrFactor A DstFactorA | 开启混合,并设置混合因子 | 混合因子不同 | Blend SrcAlpha OneMinusSrcAlpha,One Zero |
BlendOp BlendOperation | 使用BlendOperation对它们进行其他操作 | BlendOp Min |
混合因子
参数 | 因子 | 混合RGB等式 混合因子 | 混合A等式 混合因子 |
---|---|---|---|
One | 1 | Blend One One 线性减淡 | Blend OneMinusDstColor One == Blend One OneMinusSrcColor 滤色 |
Zero | 0 | Blend DstColor Zero 正片叠底相乘 | Blend DstColor SrcColor 两倍相乘 |
SrcColor | 源颜色值 | ScrColor的RGB分量 | ScrColor的A 分量 |
SrcAlpha | 源颜色的透明度值A通道 | ||
DstColor | 源颜色值 | DstColor的RGB分量 | DstColor的A 分量 |
DstAlpha | 源颜色值 | ||
OneMinusSrcColor | 1-源颜色 | 结果的RGB分量 | 结果的A分量 |
OneMinusSrcAlpha | 1-源颜色的透明度值 | ||
OneMinusDstColor | 1-目标颜色 | 结果的RGB分量 | 结果的A分量 |
OneMinusDstAlpha | 1-目标颜色的透明度值 |
混合操作
操作 | 描述 | 等式 | 例子 |
---|---|---|---|
Add | 混合后的源、目标颜色相加 | O = Src * Srbg + Dst * Drgb | BlendOp Add |
Sub | 混合后的源颜色减去混合后的目标颜色 | O = Src * Srgb - Dst* Drgb | |
RevSub | 混合后的目标颜色-混合后的源颜色 | O = DstDrgb - Src Srgb | |
Min | 使用源颜色和目标颜色中较小的值,逐分量比较 | O = min(Sr,Dr),min(Sg,Dg) | 变暗 BlendOp Min Blend One One |
Max | 使用源颜色和目标颜色中较大的值,逐分量比较 | O = max(Sr,Dr),max(Sg,Dg) | 变亮 BlendOp Max Blend One One |
混合类型
/*********************************************************
透明度混合
1.使用混合命令 Blend
**********************************************************/
Shader"AlphaBlend"{
Properties{
_Color("Color Tint", Color) = (1,1,1,1)
_MainTex("Main Tex", 2D) = "white"{}
_AlphaScale("Alpha Scale", Range(0,1)) = 0//控制整体的透明度
}
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"
struct a2v{
float4 vertex :POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOOR0;
float3 worldNormal:TEXCOORD1;
float2 uv:TEXCOORD2;
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
half _AlphaScale;
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 wNormal = normalize(i.worldNormal);
fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texcoord = tex2D(_MainTex, i.uv);
fixed3 albedo =texcoord .rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENDT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wLightdir));
fixed3 color = ambient + diffuse;
return fixed4(color, texcoord.a * _AlphaScale);
}
ENDCG
}
}
FallBack "Transparent/VertexLit"
}
- 半透明效果
/*********************************************************
开启深入写入的半透明效果
1.第一个Pass开启深度写入,但不输出颜色
2.第二个Pass进行正常的透明度混合
**********************************************************/
Shader"AlphaBlendZW"{
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{
ZWrite On //开启深度写入
ColorMask 0 //改Pass不写入任何颜色通道,不输出任何颜色
}
Pass{
Tags{"LightMode" = "ForwardBase"}
ZWrite Off
Blend ScrAlpha OneMinusSrcAlpha
CGPROGAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
struct a2v{
float4 vertex : POSITION;
float3 normal: NORMAL;
float4 texcoord:
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float2 uv:TEXCOORD2;
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale;
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);
}
fixed4 frag(v2f i):SV_Target{
fixed3 wnormal = normalize(i.worldNormal);
fixed3 wlightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texcoord = tex2D(_MainTex, i.uv);
fixed3 albedo = texcoord.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wnormal, wlightdir));
fixed3 color = ambient + diffuse;
return fixed4(color, texcoord.a * _AlphaScale);
}
ENDCG
}
}
FallBack "Diffuse"
}
ColorMask :设置颜色通道的写掩码
语义 ColorMask RGB | A | 0 | 其他任何RGBA的组合
- 双面渲染的透明效果
/*********************************************************
透明度测试的双面渲染
1.Pass中使用Cull指令关闭剔除
*********************************************************/
Shader "AlphaTestBothSize"{
properties{
_Color("Color Tint", Color) = (1,1,1,1)
_MainTex("Main Tex", 2D) = "white"{}
_CutOut("Cullout", Range(0,1)) = 0
}
SubShader{
Tags{"Queue"="AlphaTest" "IgnoreProjector" = "True" "RenderType"="TransparentCutout"}
Pass{
Tags{"LightMode" = "ForwardBase"}
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float3 texcoord:TEXCOORD0;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
float2 uv:TEXCOORD2;
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _CutOut;
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 wNormal = normalize(i.worldNormal);
fixed3 wlightdir = normalize(UnityWorldSpaceLightDir(v.worldPos));
fixed4 texcoord = tex2D(_MainTex, i.uv);
Clip(texcoord.a - _CutOut);
fixed3 albedo = texcoord.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wlightdir));
fixed3 color = ambient + diffuse;
return fixed4(color, 1);
}
ENDCG
}
}
FallBack "Transparent/Cutout/VertexLit"
}
Cull 控制需要剔除哪个面的渲染图元
语法:Cull Back | Front | Off
Back:背对摄像机的渲染图元不会被渲染
Front:朝向摄像机的渲染图元不会被渲染
Off:关闭剔除功能
-透明度混合的双面渲染
/*********************************************************
透明度混合的双面渲染
1.第一个Pass只渲染背面
2.第二个Pass只渲染正面
**********************************************************/
Shader"AlphaBlendBothSide"{
Properties{
_Color("Color Tint", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = "white"{}
_AlphaScale("Alpha Scale", Range(0,1)) = 0.5
}
SubShader{
Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
CGINCLUDE
#include "Lighting.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal :NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 pos :SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCCOOR1;
float2 uv:TEXCOORD2;
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale;
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 wNormal = normalize(i.worldNormal);
fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texcoord = tex2D(_MainTex, i.uv);
fixed3 albedo = texcoord.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal,wLightdir));
fixed3 color = ambient + diffuse;
return fixed4(color, texcoord.a * _AlphaScale);
}
ENDCG
Pass{
Tags{"LightMode" = "ForwardBase"}
ZWrite Off
Cull Front
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass{
Tags{"LightMode" = "ForwardBase"}
Cull Back
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
FallBack "Transparent/VertexLit"
}
总结:
效果 | 缺陷 | 原因 | |
---|---|---|---|
透明测试 | 效果极端,不是完全透明,就是完全不透明 | 边缘参差不齐,有锯齿 | 在边界处纹理的透明度的变化精度 |
透明度混合 | 半透明 | 若模型本身有复杂的遮挡关系时,会产生错误的透明效果 | 关闭深度入,无法对模型进行像素级别的深度排序 |
开启深度写入的半透明效果 | 与背景混合,但模型内部不会有半透明效果 | 多使用一个Pass,对性能有影响 | |
透明度测试的双面渲染 | 可以透过镂空区域看到内部渲染结果 | ||
透明度混合的双面渲染 | 保证背面总是在正面被渲染之前渲染 | 渲染顺序很重要 |