目录
1、BlendOp Sub,Alpha为0.7,混合因子不变情况
四、关于Queue为Transparent时,是否默认关闭深度写入的问题再次进行探讨和说明。
一、BlendOp混合操作
混合操作
Add
将混合后的源颜色和混合后的目标颜色相加。默认的混合操作。使用的混合等式是:
O(rgb) = SrcFactor * S(rgb) + DstFactor * D(rgb)
O(a) = SrcFactorA * S(a) + DstFactorA * D(a)
Sub
用混合后的源颜色值减去混合后的目标颜色。使用的混合等式是:
O(rgb) = SrcFactor * S(rgb) - DstFactor * D(rgb)
O(a) = SrcFactorA * S(a) - DstFactorA * D(a)
RevSub
用混合后的目标颜色值减去混合后的源颜色。使用的混合等式是:
O(rgb) = DstFactor * D(rgb) - SrcFactor * S(rgb)
O(a) = DstFactorA * D(a) - SrcFactorA * S(a)
Min
使用源颜色和目标颜色中较小的值,是逐分量比较的。使用的混合等式是:
O(rgba) = ( min( S(r), D(r) ), min(S(g),D(g)), min(S(b),D(b)), min(S(a),D(a)) )
Max
使用源颜色和目标颜色中较大的值,是逐分量比较的。使用的混合等式是:
O(rgba) = ( max( S(r), D(r) ), max(S(g),D(g)), max(S(b),D(b)), max(S(a),D(a)) )
其他逻辑操作 仅在DirectX 11.1 中支持
二、Blend混合因子
混合因子
One 1
Zero 0
SrcColor 源颜色值(RGBA):当用于混合RGB通道时,混合因子为SrcColor.rgb;当混合A通道时,混合因子为SrcColor.a
SrcAlpha 源颜色的透明度值(A通道)
DstColor 目标颜色值(RGBA):当用于混合RGB通道时,混合因子为DstColor.rgb;当混合A通道时,混合因子为DstColor.a
DstAlpha 目标颜色的透明度值(A通道)
OneMinusSrcScolor (1 - 源颜色值(RGBA)):当用于混合RGB通道时,混合因子为(1 - 源颜色值(RGBA)).rgb;当混合A通道时,混合因子为(1 - 源颜色值(RGBA)).a
OneMinusSrcAlpha 1 - 源颜色的透明度值(A通道)
OneMinusDstScolor
(1 - 目标颜色值(RGBA)):当用于混合RGB通道时,混合因子为(1 - 目标颜色值(RGBA)).rgb;当混合A通道时,混合因子为(1 - 目标颜色值(RGBA)).a
OneMinusDstAlpha 1 - 目标颜色的透明度值(A通道)
三、实战
(Alpha为0.7)
Shader "Unlit/BlendShaderTest"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_Alpha("Alpha", Range(0,1)) = 1
}
SubShader
{
Tags{
"Queue" = "Transparent" //必須是透明通道才可混合
}
BlendOp Add //相加混合
Blend SrcAlpha OneMinusSrcAlpha //RGB和A通道混合因子均为源Alpha、1-源Alpha
//BlendOp Add相加混合对应如下两个公式分别为RGB混合公式和A混合公式
//
//O(rgb) = SrcFactor * S(rgb) + DstFactor * D(rgb)
//代入因子为 输出RGB = 源Alpha值 * 源RGB值 - (1-源Alpha值) * 目标RGB值 [源是指当前片元着色器输出的颜色值、目标是指颜色缓冲区本身存在的值]
//假如_Alpha为0.3,片元着色器输出(1,0,0,0.3),目标颜色值为(1,1,1,1)
//公式为 输出RGB = (1,0,0) * 0.3 + (1-0.3) * (1,1,1) = (0.3+0.7, 0.7, 0.7) = (1, 0.7, 0.7)
//简单理解为削弱0.7倍片元着色器输出颜色值,削弱0.3倍颜色缓冲区颜色值,再将相加混合,形成新的RGB值,至此完成RGB混合
//O(a) = SrcFactorA * S(a) + DstFactorA * D(a) [Alpha值混合同理]
//输出Alpha值 = 源Alpha值 * 源Alpha值 - (1-源Alpha值) * 目标Alpha值
//其实,当没有Alpha混合因子时,可以直接用 O(rgba) = SrcFactor * S(rgba) + DstFactor * D(rgba) 来运算混合后的RGBA
//假如我混合因子为:Blend SrcAlpha OneMinusSrcAlpha 1 0
//此时后两个数值显式指明Alpha混合因子为1和0,代入公式可得知是为了忽略目标Alpha值对混合的影响
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Alpha;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.a = _Alpha; //片元着色器输出即为源颜色
return col;
}
ENDCG
}
}
}
1、BlendOp Sub,Alpha为0.7,混合因子不变情况
很明显变暗了,因为先削弱源颜色0.3倍,再减去目标颜色削弱0.7倍后的颜色值,整体上RGBA都会变小。(其他情况自行测试),用的最普遍的情况还是BlendOp Add,混合因子也是SrcAlpha OneMinusSrcAlpha。
四、关于Queue为Transparent时,是否默认关闭深度写入的问题再次进行探讨和说明。
结论:深度写入默认是开启的,不因其他因素而影响!途中发现一些比较好复习以前透明章节的内容,下面来说明。
两个透明物体,一个红色和一个原色,并【开启了深度写入】有如下两种情况:
物体相交并穿插,按照透明物体是根据离摄像机越远的越先渲染原则,红色的箱子先渲染,原色箱子后渲染,因此红色部分渲染出来了,再到原色前半部分渲染~即这一部分会渲染,后半部分因为无法通过深度测试,无法渲染出来。
物体相交并穿插,但很明显,原色离摄像机最远,先渲染原色,再渲染红色,注意!!注意!!是开启了深度写入的!
此时,原色最靠近摄像机的前端,如下圈出来的部分,这部分的深度先进行写入了深度缓冲区!导致红色被遮挡的部分无法渲染,从而出现了看似两个物体属于不透明物体的遮挡情况,实际上它们是透明物体。
下图能够更加清晰地证明它们是一个透明物体,
这一部分的原色箱子的深度先写入,导致红色部分无法渲染。
但不影响上方这部分,即使是先渲染了原色箱子,但是由于原色箱子这部分的深度值,比红色箱子更大(我理解深度值为与摄像机的距离,只要有比深度缓冲区的深度值小,就能够渲染这个片元),所以红色箱子这部分(深度值更小)能够正常渲染出来并混合原色箱子,呈现出透明效果!
(如有误解,请私信或评论留言,吐槽什么的都可以~)