ShadowMap DX9

 ShadowMap基本的思想很简单,首先从聚光灯角度对场景建立并保存场景深度。然后在正常渲染场景中,比较每个渲染点到灯的距离值(或者说到灯的深度值)是否比对应的已经建立在场景深度中的值要大,也就是说要远,如果远证明从当前视点观察的此点在灯角度中看不见,所以该渲染点处于阴影中,否则,不然。

 

首先分析一下ShadowMap的优劣:

优点:
ShadowMap只适合较近距离的阴影投射,由于32位浮点数的精度有限,所以在较远距离下,会将在阴影边界附近出现错误现象。一种是隐隐约约的阴影(即阴影中带有很多亮斑)。一种是阴影偏移并缩小。上述是比较严峻的劣势,另外的一些就是常说的锯齿,这些还算可以忍受。一般可以采用多重采样要减轻这个状况。再就是如果要使用点光源的话,需要都整个场景建立深度值,这样就需要立方体纹理,也就是CubeMapping。

缺点:
虽然有如此多的缺点,但其优点确也是很值得关注的。在近景下十分不错,而且ShadowMap的资源需求小,仅仅一张纹理。特别是其不会随着场景复杂而附加计算负担这点。能给恒定帧率提供保证。

 

在ShadowMap中给我纠正的一个最大误解就是,如何计算场景物体的点到灯的距离。不是我原本想想的那样,在ps(Pixel Shader)中一个一个的求平方再开平方根求距离(其实这根本就是错的,因为我们用的是深度值,并不是距离)。而是采用和建立的ShadowMap一样的方法,就是将场景变换到灯的投影空间,然后用z处于w,得到范围在0-1的z值也就是深度值。具体后面会提到。

 

ShadowMap案例中的大体思想知道后,欠缺的仅仅是一些编程接口的了解和使用。由于程序思路很清晰就不说程序的逻辑过程的!(不过看DX9对应的sample中代码,觉得不够条理,这个MS的员工写代码的时候可能在打盹) 

 

还是主要谈一下经验和重点,基本上也是编程中遇到的需要注意的地方。

 

个人经验:

ShadowMap中的阴影纹理啊
通过重新编写sample,我获得如下经验:

  1. 在阴影纹理创建中特别需要注意的是,包含阴影纹理的表面不能采用mip链。因为我们只需要一个表面,不需要那些mip链中的小表面。如果采用mip链后果将是很可怕的。因为采用后就会就导致使用mip链进行过滤得出深度值。而经过过滤的深度值是没有意义的。其实我查这个bug,查了5个小时,最后才发现是创建纹理时错误地把0传递给参数mipLeve,而0给mipLeve将会给表面创建mip链。而这是完全多余和错误的。
  2. 添加判断的偏移量是必须的,因为float的误差,添加很小的量给建立的场景缓存是需要的,这样最大程度减轻一个错误症状,它就是把不在阴影区错误的弄成阴影区的症状。
  3. 设置给灯的投影矩阵必须采用宽高比为1的矩阵,因为一般阴影纹理都采用正方形纹理。(此点后来证明不必要,只要第四点满足就可以)
  4. 两次建立的灯投影矩阵必须一样。这两次分别是给场景建立深度值是采用的矩阵,另一个是在正常渲染中,为了得到渲染点相对于灯的深度值所采用的灯的投影矩阵。特别是建立两次矩阵是采用的的近裁截面和远裁截面必须一致,否则两次得到的深度值之间没有可比性,因为投影空间中渲染点的深度值是通过用近裁截面和远裁截面之间的距离压缩得来的的。
  5. 投影空间中,x,y的范围是(-1~1),需要将其投射都纹理空间(0~1)并且需要注意纹理空间和投影空间y的反向。

其实上面提到的投影矩阵应该说是灯的是视矩阵和灯的投影矩阵的乘积。单独说投影矩阵只是为了不累赘。


另外一些知识点:

创建ShadowMap纹理时,采用F32的浮点数据类型,对应的格式是D3DFMT_R32,用D3DFMT_R32是将4字节解读为单独的红色通道,并且是浮点数表示的。虽然在ps中需要返回的颜色变量还是float4,但是只需要指定其x分量即可。同样在tex2D中我们也只需要查看其中的x分量就可以。

 

很开心!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值