Directx11教程二十五之ZBuffer(深度缓存,DepthBuffer)

这节教程的结构如下:




一,DepthBuffer(深度缓存)

深度缓存(Z缓存值)是用来记录视截体的每个像素的深度,其值范围是[0,1],在D3D11中 默认近裁剪面(Near_Z)上面的像素深度为0,而远裁剪面上的像素的像素深度为1, 注意stencilBuffer一般都是跟DepthBuffer绑定在一起的,创建DepthBuffer 时,指定数据格式 DXGI_FORMAT_D24_UNORM_S8_UINT.,   
其中深度缓存值中有24位用来存储真正的深度缓存值(Z值),有8位用来存储模板缓存值。

如图所示:



默认情况下   对于背后缓存的同一个位置的像素,Z缓存值小的将代替Z缓存值大的像素,即所谓的Z缓存测试剔除。

那么Z缓存值怎么求出来呢?

我一步一步的说出来,首先来看看D3D11渲染流水线:







首先说明一点,真正意义上的透视投影过程由两步组成:(1)乘以投影矩阵   (2)透视除法

第一步:乘以投影矩阵 ( Projection matrix ),变换到齐次裁剪空间 ( Homogeneous clip space ),并进行CVV裁剪
假设在相机空间(View Coordinate System) 一个顶点的坐标为(x,y,z,1),则该变乘以投影矩阵( Projection matrix)后,变换到齐次裁剪空间,
此时坐标变为(Xp,Yp,Zp,Wp),此时W不为1,因此称作为齐次坐标,给出此时坐标分值Xp,Yp,Zp的范围, 
-Wp=<Xp<=Wp   -Wp=<Yp<=Wp     0=<Zp<=Wp

这时将进行CVV裁剪算法( 其实这裁剪算法 也不能算CVV裁剪,下面会说原因)

第二步,进行透视除法,变换到NDC空间(Normalized Device Coordinate)

有上面可以知道齐次裁剪空间内 顶点 (Xp,Yp,Zp,Wp)  -Wp=<Xp<=Wp   -Wp=<Yp<=Wp     0=<Zp<=Wp,

进行透视除法,就是将顶点(Xp,Yp,Zp,Wp)每个分值除以Wp,得到(Xn,Yn,Zn,1),其中
  (Xn,Yn,Zn,1)

规则观察体(Canonical View Volume)称为CVV,人们称之为CVV,感觉大量人误认为是单位立方体(或者长方体),这里我跟着他们一起错,规定CVV也是单位立方体,而不是规则观察体。(其实按单词字面意思,立方体或者长方体不管是不是单位的都应该算是CVV,毕竟都是规则的,但是这里我跟着他们一起错吧,就认为是单位的)
上面说了这些也就是想表达一个意思:真正的透视投影过程不仅仅是乘以投影矩阵就行了,还需要进行接下来的透视除法。
当然很多人以为是在NDC空间进行裁剪的,也就是(Xn,Yn,Zn,1),-1=<Xn<=1,-1=<Yn<=1,0=<Zn<=1这样的空间进行裁剪,这样是错误的想法







这里给出两篇大牛的文章,深入论述了““透视投影变换的””的来龙去脉。





这里放出文章部分截图 证明我的观点:(这是关于opengl的投影变换原理说明,-1=< Z(opengl)<=1,   0= < Z (d3d11 )<1.0,但无伤大雅,照样可以理解)
不过这作者感觉有些论述自相矛盾,原因是最上面3D渲染流水线图也是该作者给出的,文章在这里   http://blog.csdn.net/popy007/article/details/5120158




然而我们在Shader里指定系统签名“”SV_POSITION” 之后 裁剪算法和透视除法是显卡自动自动进行.,不用我们操心,而如果使用我们自己定义的签名“”POSITION“”,透视除法并不会自动进行,也就是乘以投影矩阵后(投影变换后)得到的坐标(Xp,Yp,Zp,Wp)   -Wp=<Xp<=Wp   -Wp=<Yp<=Wp     0=<Zp<=Wp

       那么在齐次裁剪空间     0.0=<Zp/Wp<=1.0      Z缓存值=Zp/Wp;


当然我这里主要是关于D3D11渲染管线的,opengl的参见OpenGL渲染流水线之世界矩阵,相机变换矩阵,透视投影变换矩阵


下面放出我的Shader代码:
//VertexShader
cbuffer CBMatrix:register(b0)
{
	matrix World;
	matrix View;
	matrix Proj;
};

struct VertexIn
{
	float4 Pos:POSITION;
};


struct VertexOut
{
	float4 Pos:SV_POSITION;
	float4 Pos_Depth:POSITION;
};


VertexOut VS(VertexIn ina)
{
	VertexOut outa;

	//------齐次裁剪空间-----(x,y,z,w)  -w=<x<=w -w=<y<=w  0=<z<=w  由于标记“SV_POSITION”,貌似之后会进行CVV裁剪,       // 这时透视除法和CVV裁剪是显卡自动进行的
	outa.Pos = mul(ina.Pos, World);
	outa.Pos = mul(outa.Pos, View);
	outa.Pos = mul(outa.Pos, Proj);

	//顶点坐标,由于没标记“SV_POSITION”,不会自动进透视除法,一直停留在齐次裁剪空间
	outa.Pos_Depth = outa.Pos;
	return outa;
}

float4 PS(VertexOut outa) : SV_Target
{
	float4 color;
    float Z;
    //求出每个像素的Z缓存值  0.0=<(Z缓存值=Zp/Wp)<=1.0
	Z = outa.Pos_Depth.z / outa.Pos_Depth.w;

	//当Z缓存值小于0.9f时,显示为红色,占据了大部分的屏幕,Z越小,越接近屏幕
	if (Z < 0.9f)
	{
		color = float4(1.0, 0.0f, 0.0f, 1.0f);
	}

	//当Z缓存值大于0.9f而小于0.95f时为绿色
	if (Z > 0.9f)
	{
		color = float4(0.0, 1.0f, 0.0f, 1.0f);
	}

	//当Z缓存值大于0.925f为蓝色
	if (Z > 0.925f)
	{
		color = float4(0.0, 0.0f, 1.0f, 1.0f);
	}

	return color;
	
}



放出我的程序运行图:





下面我的源代码链接:

   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值