代码改变世界

(原)关于alpha穿透阴影的问题

2010-05-29 16:08  六水  阅读(753)  评论(0编辑  收藏  举报

如引用,请注明出处:http://www.cnblogs.com/sixwater

关于实时可穿透性阴影的问题,前段时间做了基于shadowmap的alpha可穿透性阴影:(场景来自far cry)

images/alphashadow.jpg


这是打开了alpha的实时阴影.可以发现,树叶的影子,已经是斑驳的样子,可以对比一下下图,没有打开alpha穿透的影子.

images/noalphashadow.jpg


问题的发现
但是这时候的影子也太过斑驳了,影子太少,太稀疏.
仔细观看,其实是有BUG的.这个BUG源自我的算法.

问题分析
当时为了实现穿透性阴影,我在渲染到z-map的时候,象素SHADER阶段也是渲染纹理的,
并且检测该象素的alpha,如果alpha大一某个alphaRef值的时候,我就正常输出该象素的
深度(基于灯光视角),而相反,透明的区域,我当时直接输出一个很大的数(先用代
bigNum表示,而为什么是bigNum,写过shadowmap的人都知道吧.)。
结果是,树叶的阴影是对的,但树干的阴影却有错误。因为有一种情况是这样的:树叶
以下的地方还有物体,譬如树干。而如果渲染的时候我先渲染了树干然后再渲染树叶
(在最后的渲染阶段其实应该这样渲染),那改点的深度值就被后来的值(bigNum)覆
盖了。

解决BUG
深度图抛弃现在的R32F格式,使用A8R8G8B8格式,绘制到深度图的时候,要读取纹理,输出的时候,
需要输出该纹素的alpha。return float4(a,b,c,alpha),把depth压缩到a、b、c,读取的时候再解压.
至于如何压缩,解压,可参考GPU GEM1。其实GG1是建议使用A8R8G8B8格式的深度图的,因为该格式
比R32F更加通用,有些显卡还不支持R32F呢,而且整数纹理的渲染是比较快速的。
这办法不是很好,因为精度只有24位了。
如果大家有好的办法,请告诉我哦。。。呵呵

另外的办法
依然使用R32F,但在渲染到shadowmap的ps里,使用物体纹理像素里的alpha,
譬如return float4(depth,0,0,alpha);经过测试,这种方法, 在nv 8 系列的显卡上能正常进行alpha穿透,
但在7系的显卡就不行了,因为用的R32F格式并没有alpha通道。 目前还不知道8系的为什么可以。

最终解决方案是,依然使用R32F,结合指令clip,
在渲染到shadowmap的ps里,使用alpha计算:
clip(tex.a-0.5f);
return float4(depth,0,0,1);

那么alpha小于0.5的像素就被剔除掉。