unity shader 透明效果

两种透明模式:

1.透明度测试,2.透明度混合
透明度测试不能实现半透,只会删除一些片元,看上去像镂空一些面

渲染顺序:

1
2
3
4
5
6
7
8
9
10
11
//需要半透
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass {
ZWrite Off //关闭深度测试
……
}
}

//透明度测试
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}

上面的相关参数请参照: 这篇文章的Queue和RenderType部分

透明度测试

没什么好讲的,根据条件(比如texcolor.a是否>参数)调用 clip() discard()丢弃片元
image

透明度混合

书中讲了3种方法,实现了三种效果:

  1. 单面的半透明[虽然有透明效果,但是未显示背面颜色]
    image

模型交叉时会出错
image

  1. 开启深度写入的单面半透明[模型交叉时,摄像机后方的被遮蔽]
    image

  2. 双面渲染的透明[解决单面的半透明看不到底下颜色的问题]
    image

重要命令:Blend

在解释代码前需要了解此命令
请参照: 这篇文章 的Blend部分

实现原理解析

1. 单面渲染

关闭ZWrite,根据Output = SrcAlpha SrcColor + (1-SrcAlpha) DstColor 计算颜色。
计算颜色与之前计算光不同的是,此处color.a为材质上此像素的a,乘以输入的透明度放大系数。
但是由于ZWrite的关闭,有些交叉的模型会出现显示错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass {
Tags { "LightMode"="ForwardBase" }

ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

……

fixed4 frag(v2f i) : SV_Target {
……
return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
}
}

2. 开启深度写入

上者说到显示有错,修改方案为:使用两个Pass,第一个参数开启ZWrite,让其对深度排序,第二个Pass在混合时可以按照之前的深度排序进行透明渲染。
shader重要修改如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
……
}
}

3.双面渲染

解决方案为使用两个Pass,一个Pass只渲染背面,第二个只渲染正面,由此保证正面在背面之后渲染。实现方式第一个Pass中Cull Front 第二个Cull Back
交叉的模型仍然会出现问题,但是可以解决单面不显示背面颜色的问题。

然而以上三种方法以及合并深度写入与双面渲染,在两个透明物体有部分重叠的时候,都分别有各自不合理之处,详见:三种透明度混合各自的bug 文档

书中双面透明代码