赞
踩
透明度测试和透明度混合都是用来处理半透明效果的手段.
在裁剪测试之后, 如果有一些半透片元需要抛弃(比如png纹理的多余空白), 可以通过透明度测试达到目的.
在深度测试通过之后, 渲染管线进入混合阶段, 在混合阶段处理不透明物体或者半透物体的颜色混合.
我们先说明不透明物体的处理过程.
深度测试通过之后, 相互遮挡的不透明物体开始进行颜色混合, 所谓颜色混合就是如何处理源颜色(待渲染的片元颜色)和目标颜色(颜色缓存中已经存储的片元颜色).
默认情况下的操作就是使用源颜色覆盖目标颜色. 当然我们可以通过给混合函数传递不同的参数来改写操作.
接下来说说有透明效果的物体的处理过程.
有透明效果说明我们想要的是透过该物体可以看到起后面的物体, 但是如果采用默认的混合操作, 会使用透明物体的颜色更新颜色目标颜色, 我们就无法看到后面的物体了, 所以对于透明物体需要单独处理. 当然, 如果是不透明物体遮挡透明物体, 则采用默认的行为即可.
现在常用的手段有两种, 一个是透明度测试, 一个是透明度混合.
透明度测试很简单, 就是在处理片元时, 给定一个阈值, 如果片元的透明度低于该值, 则抛弃该片元. 一般通过api提供的Clip
函数完成. 如下:
// 模拟实现 void clip(value) { if (value < 0) discard; } // Unity的片元着色器 fixed4 frag(v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor = tex2D(_MainTex, i.uv); // Alpha test 若texColor.a小于_Cutoff,则物体完全透明 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)); return fixed4(ambient + diffuse, 1.0); }
透明度测试一般用来过滤一些不受关注的透明片元, 并不是主流的透明物体处理方案, 因为它的结果是非此即彼, 就是说要么完全看得到, 要么完全看不到.
半透物体的处理主要还是使用透明度混合, 原理也十分简单, 就是在混合阶段使用片元的透明度来处理颜色混合, 具体实现是通过给混合函数传递透明度相关的参数.
Unity中使用Blend
函数和BlendOp
函数来处理混合操作.
混合的原理是分别对源颜色和目标颜色做颜色和透明度的处理:
Blend
用于开关混合功能, 可能的参数有:
Blend Off
: 关闭混合, 直接覆盖目标颜色Blend srcFactor destFactor
: 使用相同的混合因子混合颜色和透明度Blend srcFactor destFactor, srcFactorA destFactorA
: 使用不同的混合因子混合颜色和透明度混合因子可能的取值有:
One
: 1Zero
: 0SrcColor
: 使用源颜色作为混合因子, 源颜色的rgb作为颜色混合因子, alpha作为透明度混合因子DstColor
: 使用目标颜色作为混合因子, 目标颜色的rgb作为颜色混合因子, alpha作为透明度混合因子SrcAlpha
: 使用源颜色的alpha作为rgb和alpha的混合因子DstAlpha
: 使用目标颜色的alpha作为rgb和alpha的混合因子OneMinusSrcColor
: 与SrcColor
类似, 只不过是将各个分量被1减之后得到的颜色作为混合因子OneMinusDstColor
: 与DstColor
类似, 只不过是将各个分量被1减之后得到的颜色作为混合因子OneMinusSrcAlpha
: 与OneMinusSrcColor
类似, 只不过是将alpha被1减之后得到的alpha作为混合因子OneMinusDstAlpha
: 与OneMinusDstColor
类似, 只不过是将alpha被1减之后得到的alpha作为混合因子Unity默认参数是Blend One Zero
, 使用源颜色覆盖目标颜色.
一般渲染半透明物体时使用Blend SrcAlpha OneMinusSrcAlpha
.
BlendOp
用于定义源颜色和目标颜色分别混合后进行的操作, 默认是BlendOp Add
:
Add
: 加Sub
: 减RevSub
: 目标-源Min
: 目标和源各个分量分别进行取较小值(是混合之前的颜色, 此参数下混合因子不生效)Max
: 目标和源各个分量分别进行取较大值(是混合之前的颜色, 此参数下混合因子不生效)默认情况下, Unity会做表面剔除(通过Cull Front/Back
来剔除正面或者背面), 也就是说会将物体内外某个方向的面去掉以提高渲染效率.
在渲染半透明物体时, 有时我们希望透过半透明部分看到物体内部, 比如通过窗户来看到屋子里的内容, 就可以关闭剔除效果Cull Off
来达到目的.
有些半透明物体内部互相交叉会导致渲染错乱, 如下:
可以通过双面渲染解决, 双面渲染就是使用两个Pass
来分两次分别渲染物体的正面和背面:
Pass{
// 剔除正面
Cull Front
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
// ... 着色
}
Pass{
// 剔除背面
Cull Back
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
// ... 着色
}
今天主要对透明度测试和颜色混合还有半透明物体的渲染做了基本的介绍.
半透明物体的渲染在业界一直是一个比较复杂的问题, 今天的内容只是能够解决大部分情况, 还有一些特殊情况需要特殊处理.
希望对大家有所帮助.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。