Stencil buffer

Stencil buffer 

模版缓冲(stencil buffer)或印模缓冲,是在OpenGL三维绘图等计算机图像硬件中常见的除颜色缓冲、像素缓冲、深度缓冲之外另一种数据缓冲。词源模版(stencil)是指一种印刷技术,通常以蜡纸或者钢板印刷文字或图形;区别于模板(template),用木板为外形修剪的依据来复制形状;模版(stencil)是指印模,而模板(template)主要是指形模。模版缓冲是以像素为单位的,整数数值的缓冲,通常给每个像素分配一个字节长度的数值。深度缓冲与模版缓冲经常在图形硬件的随机存取内存(RAM)中分享相同的区域。

模板缓冲所在的是整个流水线的最后一个阶段,这个阶段的流水线如下





最简单的情况,模版缓冲被用于限制渲染的区域。更多高级应用会利用深度缓冲与模版缓冲的在图形渲染流水线中的强关联关系。例如,模版的数值可以按每个像素是否通过深度测试来自动增加或减少。

简单组合使用深度测试与模版修饰符可以使得大量的本来需要多次渲染过程的效果(例如阴影、外形的绘制或复合几何图元(Geometric primitive)的交叉部分的高光处理)可以简单实现,因此减轻了图形硬件的负担。

最典型的应用是给三维图像加阴影。也用于平面反射。

其它渲染的技术,例如,视口渲染(portal rendering),利用模版缓冲作其它用途。例如,它可以被用于查找被视口遮蔽的屏幕区域然后重新正确渲染这些像素点。

模版缓冲与其修饰符可以通过OpenGL或Direct3D的应用程序编程接口(API)来访问。





常用的比较操作


 
GreaterOnly render pixels whose reference value is greater than the value in the buffer.
GEqualOnly render pixels whose reference value is greater than or equal to the value in the buffer.
LessOnly render pixels whose reference value is less than the value in the buffer.
LEqualOnly render pixels whose reference value is less than or equal to the value in the buffer.
EqualOnly render pixels whose reference value equals the value in the buffer.
NotEqualOnly render pixels whose reference value differs from the value in the buffer.
AlwaysMake the stencil test always pass.
NeverMake the stencil test always fail.

模版像素操作


 
KeepKeep the current contents of the buffer.
ZeroWrite 0 into the buffer.
ReplaceWrite the reference value into the buffer.
IncrSatIncrement the current value in the buffer. If the value is 255 already, it stays at 255.
DecrSatDecrement the current value in the buffer. If the value is 0 already, it stays at 0.
InvertNegate all the bits.
IncrWrapIncrement the current value in the buffer. If the value is 255 already, it becomes 0.
DecrWrapDecrement the current value in the buffer. If the value is 0 already, it becomes 255.


Zfail
What to do with the contents of the buffer if the stencil test passes, but the depth test fails. Default: keep.

例子


下面是Unity文档里的例子,文档有点错误,按照文档的代码是写不出对应的结果的。

首先在场景里放一个红球,Shader如下
Shader "Custom/RedStencil" {

	SubShader {
		  Tags { "RenderType"="Opaque" "Queue"="Geometry"}
        Pass {
            Stencil {
                Ref 2
                Comp always
                Pass replace
                ZFail decrWrap
            }
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            struct appdata {
                float4 vertex : POSITION;
            };
            struct v2f {
                float4 pos : SV_POSITION;
            };
            v2f vert(appdata v) {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                return o;
            }
            half4 frag(v2f i) : SV_Target {
                return half4(1,0,0,1);
            }
            ENDCG
        }
		}
}

结果如下




stencil的值在球体绘制的地方被赋为2,没有绘制的地方为0.

接下来画绿色的球
Shader "Custom/GreenStencil" {
	SubShader {
 Tags { "RenderType"="Opaque" "Queue"="Geometry+1"}
        Pass {
            Stencil {
                Ref 2
                Comp equal
                Pass keep 
                Fail decrWrap 
                ZFail IncrSat
            }
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            struct appdata {
                float4 vertex : POSITION;
            };
            struct v2f {
                float4 pos : SV_POSITION;
            };
            v2f vert(appdata v) {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                return o;
            }
            half4 frag(v2f i) : SV_Target {
                return half4(0,1,0,1);
            }
            ENDCG
        }
	} 
	FallBack "Diffuse"
}



绘制结果如下,绿色的部分是stencil pass的,绿球没有被绘制出来的地方stecil值会减一,变为255.有一部分通过的stencil test,但是没有通过ztest的,stencil值+1,变成3



最后画蓝色的球,shader如下
Shader "Custom/BlueStencil" {
	SubShader {
	  Tags { "RenderType"="Opaque" "Queue"="Overlay"}
        Pass {
            Stencil {
                Ref 3
                Comp Equal
            }
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            struct appdata {
                float4 vertex : POSITION;
            };
            struct v2f {
                float4 pos : SV_POSITION;
            };
            v2f vert(appdata v) {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                return o;
            }
            half4 frag(v2f i) : SV_Target {
                return half4(0,0,1,1);
            }
            ENDCG
        }
	}
}




蓝色球只在stencil buffer 值为3的地方绘制出来了。

参考

ShaderLab: Stencil - http://docs.unity3d.com/Manual/SL-Stencil.html
Extra buffers - https://open.gl/depthstencils
OpenGL Programming/Stencil buffer - https://en.wikibooks.org/wiki/OpenGL_Programming/Stencil_buffer

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值