渲染管线
Scissor Test
在OpengGl中通过如下方法设置裁剪
//设置裁剪矩形的位置和大小
void glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
Alpha Test
使用fragment程序时ShaderLab Alpha Test命令无效,用cg clip函数来处理。
Shader实例
树透明区域丢弃掉。
clip函数
void clip(float4 x)
{
if (any(x < 0))
discard;
}
Shader "Unlit/Clip"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_CutOff("CutOff",Range(0,1)) = 0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
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;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
float _CutOff;
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
clip(col.a-_CutOff);
return col;
}
ENDCG
}
}
}
模板测试 Stencil Test
stencil是印刷业中的版面模子,模子上抠出需要的图案,然后将模子盖在要被印刷的材质上,对抠出的洞涂颜色就可以了。
如果将屏幕上所有像素初始为0,那么stencil buffer的作用就是将某些0变为特定值1,2,3…255,每个pass之前可以决定只渲染某个特定stencil值的像素并抛弃其他像素,就像一块模板一样屏蔽所有其他非该stencil值的像素区域,只对当前stencil值的像素进行操作。
Stencil Test语法如下:
stencil{
Ref referenceValue
ReadMask readMask
WriteMask writeMask
Comp comparisonFunction
Pass stencilOperation
Fail stencilOperation
ZFail stencilOperation
}
判断依据:
if((referenceValue&readMask) comparisonFunction (stencilBufferValue&readMask))
通过像素
else
抛弃像素
-
ReferenceValue:该值用来比较(当 Comp 设置为非always)并/或 用来写入到buffer(如果任何Pass,Fail,ZFail被设置来代替他)。为 0–255 整数.
-
ReadMask:从字面意思的理解就是读遮罩,readMask将和referenceValue以及stencilBufferValue进行按位与(&)操作,readMask取值范围也是0-255的整数,默认值为255,二进制位11111111,即读取的时候不对referenceValue和stencilBufferValue产生效果,读取的还是原始值。
-
WriteMask:一个8 bit的mask,值为0-255的整数,当写入buffer时使用。注意,和其他写掩码一样,它指定的模版缓冲(stencil buffer)会被写操作影响。(例如:WriteMask 0 意味着没有bit会受影响,而不是0值会被写入)。 默认值为: 255.
-
comparisonFunction:该函数用来比较reference值和当前buffer中的内容。默认为: always.
取值 | 含义 |
---|---|
Greater | 相当于“>”操作,即仅当左边>右边,模板测试通过,渲染像素 |
GEqual | 相当于“>=”操作,即仅当左边>=右边,模板测试通过,渲染像素 |
Less | 相当于“<”操作,即仅当左边<右边,模板测试通过,渲染像素 |
LEqual | 相当于“<=”操作,即仅当左边<=右边,模板测试通过,渲染像素 |
Equal | 相当于“=”操作,即仅当左边=右边,模板测试通过,渲染像素 |
NotEqual | 相当于“!=”操作,即仅当左边!=右边,模板测试通过,渲染像素 |
Always | 不管公式两边为何值,模板测试总是通过,渲染像素 |
Never | 不敢公式两边为何值,模板测试总是失败 ,像素被抛弃 |
-
stencilOperation: 1、Pass:表示要做什么,当buffer内容通过了模板测试(以及深度测试)。 默认: keep.
2、Fail:表示要做什么,当buffer的内容没有通过模板测试。 默认: keep.
3、ZFail:表示要做什么,当buffer内容通过了模板测试,但是没通过深度测试。 默认: keep.
取值 | 含义 |
---|---|
Keep | 保留当前缓冲中的内容,即stencilBufferValue不变。 |
Zero | 将0写入缓冲,即stencilBufferValue值变为0。 |
Replace | 将参考值写入缓冲,即将referenceValue赋值给stencilBufferValue。 |
IncrSat | stencilBufferValue加1,如果stencilBufferValue超过255了,那么保留为255,即不大于255。 |
DecrSat | stencilBufferValue减1,如果stencilBufferValue超过为0,那么保留为0,即不小于0。 |
Invert | 将当前模板缓冲值(stencilBufferValue)按位取反 |
IncrWrap | 当前缓冲的值加1,如果缓冲值超过255了,那么变成0,然后继续自增。 |
DecrWrap | 当前缓冲的值减1,如果缓冲值已经为0,那么变成255,然后继续自减。 |
Shader实例
通过窗透过墙看后面的大海
//window
ZWrite Off
Stencil {
Ref 1
Comp always
Pass replace
}
//wall
Stencil {
Ref 1
Comp NotEqual
}
//sea
Stencil {
Ref 1
Comp Equal
}
Depth Test
深度
由于渲染顺序的问题,远处的物体会被近处的物体,所遮挡。 远近不是物体直接到摄像机的距离,而是做摄像机朝向垂线的距离。
深度值的精度一般有16位、24位和32位float,比较常用的深度精度为24位。
深度缓存中存储着准备要绘制在屏幕上的像素点的深度值。
-
ZWrite on / off : 开启写入深度缓冲/关闭写入深度缓冲,一般情况不透明的物体都会使用Zwrite on 而半透明的物体都会使用 ZWrite off 这样半透明的物体就直接比较ZTest了。
-
在深度缓冲区中包含深度值介于0.0和1.0之间.但是和z的关系一般不按线性关系处理。而是一个附近的物体是小的 z 值因此给了我们很高的深度精度,很远的给很低精读的深度值。
在深度测试中,默认情况是将要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新深度缓存(Detph buffer)中对应像素的颜色值(Color buffer中)。
- ZTest 分类:当前的像素来对深度缓冲中的z值进行比较的条件。
ZTest Less:深度小于当前缓存则通过
ZTest Greater:深度大于当前缓存则通过
ZTest LEqual:深度小于等于当前缓存则通过
ZTest GEqual:深度大于等于当前缓存则通过
ZTest Equal:深度等于当前缓存则通过
ZTest NotEqual:深度不等于当前缓存则通过
ZTest Always:不论如何都通过
ZWrite和ZTest使用情况:
1.当ZWrite为On时,ZTest通过时,该像素的深度才能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值也会写入颜色缓存。
2.当ZWrite为On时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。
3.当ZWrite为Off时,ZTest通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值会写入颜色缓存。
4.当ZWrite为Off时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。
Shader实例
1.红绿模型shader均为默认值,ZWrite默认值为On,ZTest默认值为LEqual
先渲染红色模型,再渲染绿色模型。
2.均为ZWrite默认值为On,ZTest为Always
3.均为ZWrite默认值为On,ZTest为GEqual
4.红色模型默认值,绿色模型ZWrite为Off,ZTest为GEqual
Offset
Z-fighting
下图可以看出z_eye与z_ndc并非线性关系。也就是说近平面具有非常高的精度,而远平面的精度很低。如果[-near,-far]的范围变得很大,会引起深度精度问题(Z-fighting):远平面附近ze的小变化不会影响z_ndc值。为了最小化深度缓存精度问题,n与f的距离应该尽可能小。
多边形偏移是一个挺有用的技巧,有时会用来解决Z-fighting。z-fighting在开启深度测试时,如果两个重叠物体的深度值非常接近,两次绘制到同一个像素时,深度值相差非常小,就无法正确的辨别究竟哪一次绘制的深度值更小.那么就也会产生z-fighting。
shader 语法
Offset Factor, Units
允许您使用两个参数指定深度偏移,Factor和Units,这允许您强制将一个多边形绘制在另一个多边形上,尽管它们实际上位于相同位置。
offset = (m * factor) + (r * units)
- Factor相对于多边形的X或Y缩放最大Z斜率.
- Units缩放最小可分辨深度缓冲值。
- m是多边形的深度的斜率(在光栅化阶段计算得出)中的最大值。这句话难以理解,你只需知道,一个多边形越是与近裁剪面(near clipping plan)平行,m就越接近0。
- r是能产生在窗口坐标系的深度值中可分辨的差异的最小值,r是由具体实现OpenGL的平台指定的一个常量。
一个大于0的offset 会把模型推到离你(摄像机)更远一点的位置,相应地,一个小于0的offset 会把模型拉近。
黄色模型设置为如下值解决二个重叠模型绘制z-fighting问题:
offset -1,0
Alpha Blend
混合命令
取值 | 含义 |
---|---|
Blend Off | 关闭混合(默认) |
Blend SrcFactor DstFactor | 片元产生的颜色xSrcFactor+屏幕上已有的颜色xDstFactor=最终的颜色(写入颜色缓存) |
Blend SrcFactor DstFactor, SrcFactorA DstFactorA | 同上,只不过使用单独的因子SrcFactorA和DstFactorA来混合透明度通道 |
BlendOp BlendOperation | 用其他的操作来取代加法混合。 |
BlendOp OpColor, OpAlpha | 同上,只不过对于透明度通道使用不同的操作。 |
混合操作(BlendOp)
取值 | 含义 |
---|---|
Add 加法: | FinalColor=SrcFactorSrcColor+DstFactorDstColor |
Sub 减法(源-目标): | FinalColor=SrcFactorSrcColor-DstFactorDstColor |
RevSub 减法(目标-源): | FinalColor=DstFactorDstColor-SrcFactorSrcColor |
Min | 较小值(逐个通道比较) |
Max | 较大值(逐个通道比较) |
混合因子(Blend)
取值 | 含义 |
---|---|
One | 混合因子1,表示完全的源颜色或目标颜色 |
Zero | 混合因子0,舍弃掉源颜色或目标颜色 |
SrcColor | 源颜色值 |
SrcAlpha | 源透明度 |
DstColor | 目标颜色值 |
DstAlpha | 目标透明度 |
OneMinusSrcColor | 1-SrcColor |
OneMinusSrcAlpha | 1-SrcAlpha |
OneMinusDstColor | 1-DstColor |
OneMinusDstAlpha | 1-DstAlpha |
Shader实例
Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
Blend SrcAlpha OneMinusSrcAlpha
blend Mode
RenderQueue
RenderQueue会改变物体被渲染的先后顺序,但是并不会改变物体的空间位置。只是针对同一个camera渲染的物体。
Tags { "Queue"="Geometry" }
需在SubShader中显示声明ZWrite Off,通知Unity我们会重写物体的渲染深度排序。
属性 | 值 | 渲染队列描述 |
---|---|---|
Background | 1000 | 这个队列通常被最先渲染(比如 天空盒)。 |
Geometry | 2000 | 这是默认的渲染队列。它被用于绝大多数对象。不透明几何体使用该队列。从前往后渲染 |
AlphaTest | 2450 | 需要开启透明度测试的物体。Unity5以后从Geometry队列中拆出来,因为在所有不透明物体渲染完之后再渲染会比较高效。 |
GeometryLast | – | 所有Geometry和AlphaTest队列的物体渲染完后 |
Transparent | 3000 | 所有Geometry和AlphaTest队列的物体渲染完后,再按照从后往前的顺序进行渲染,任何使用了透明度混合的物体都应该使用该队列(例如玻璃和粒子效果) |
Overlay | 4000 | 该队列用于实现一些叠加效果,适合最后渲染的物体(如镜头光晕)。 |
参考资料: