ShadowVolume DX9

 之前写过ShadowVolume,但是那是老版本(DX8)的DXSDK中的sample。而老版本并不是一个很好的解决方案。而DX9中的ShadowVolume还算是比较可取的方案。在这里主要对DX9中的ShadowVolume中的重点难点进行梳理。详细的细节,必须参考sample中的代码。

 

DX9中的shadowVolume最大的特点是建立了阴影体网格,而不是之前DX8中的动态生成轮廓边集合。建立阴影体网格最大的好处就是通过GPU来分担原来由CPU负责的轮廓边识别。而且由于新的阴影体积总体算法的更新,使得轮廓边识别更容易。缺点也很显然多了很多内存需求。

 

我们还是先大体了解一下基本思路。

  1. 我们的原始模型建立阴影体网格。主要的方法是为每一个面都建立单独顶点,这样面与面之间不会形成牵扯,以便进行随后的背面移动。
  2. 其次在只是用环境光的条件下渲染场景到color buffer和z buffer里面。
  3. 再关闭z buffer和 color buffer,并开通stencil buffer,使用depth-fail方法将阴影体渲染至stencil buffer中。
  4. 最后根据stencil buffer中标记识别出不在阴影的区域,并对这些区域添加正常光照。

其中在sample的代码里面最难理解的区域是GenerateShadowMesh函数。而GenerateShadowMesh中最难理解的有好几处。

首先是ConvertAdjacencyToPtRep(),这个函数是获得用点表示的相邻信息。

比如下面的四边形

其中四边形由6个顶点组成,而不是我们常见的4个顶点,在这种情况下通过ConvertAdjacencyToPtRep()我们能得到一个和顶点个数相等的一个DWORD数组,数组的下标表示顶点索引,而数组内的值就是相应位置顶点的点索引。 比如加入上图有6个顶点。

则通过此函数会得到这么一个数组

DWORD PtRep[ 6 ] =  { 0, 1, 2, 2, 1, 5  };

我们可以看到如果有顶点和以前出现的顶点相邻很近,则后出现的顶点用前者的索引。通过这个数组我们可以知道下标是3的元素和下标是2的元素的值一样,即 PtRep[ 2 ] == PtRep[ 3 ];

 

通过得到邻近信息,我们就可以借助它,识别出使用不同索引表示的相邻点,进而识别相邻边。比如在上图中我们怎么通过计算知道 边(V1-V2) 和边(V2-V3)相邻呢?

我们可以利用邻近数组PtRep,看看边(V1-V2)和边(v2-V3)是不是同一条边(暂且不管边的方向)。那么我们可以看到边 (v1-v2)是( PtRep[ 1 ], PtRep[ 2 ] ),边(V2-V3)是( PtRep[ 2 ], PtRep[ 3 ] ),也就是边( 1, 2 ) 和边( 2, 1 ). 从而我们可以看到在用邻近数组表示边的,相邻的边即使原本的顶点索引不同,但在邻近数组中都是一样。所以MS的高手们早就知道这么秒用了。

 

另外就是边映射结构体。仔细看看应该能看明白里面的逻辑。

主要是记录每条的三个信息。

  1. 在邻近数组中的边表示
  2. 相邻两条边中第一条边在普通顶点索引列表中的边表示
  3. 相邻两条边中第二条边在普通顶点索引列表中的边表示

后面的两个信息主要是用于信息保存,以便后面使用的。

 

然后稍微有点难度的就是补洞操作。这里我们十分注意在Depth-Fail技术中,阴影网格必须是全封闭。 所以补洞操作时必须的。

全封闭也就是3d中没有任何漏洞。不像在Depth-pass技术中那样只需要延伸阴影边,在这里我们需要cap。也即是阴影的前冒和后帽。实际上就是阴影网格中和物体同形状的部分。如下图所示的Cap,也就是原本物体网格的相对于灯光的前面和后面。

如果没有冒的话,在某些情况是会出现槽糕后果。例如

在No caps中利用Depth-Fail是无法在墙上绘出阴影的,因为眼睛方向对应的地方没有阴影网格。而加了Cap之后就可以在墙上绘出阴影了。

 

另外在阴影网格处理的VertexShader中,对于当物体和灯光转换到相机坐标中后,如果物体比灯在z方向上更远离视点,我们采用将物体移至远裁截面稍微靠前的位置。这样一定能让整个阴影网格不被裁减掉。以保证不会发现像No Caps图中的情况。采用的公式在sample中都写着,稍微画个图,或者想想就可以理解。然而当物体比灯在z方向上更靠近视点的,我们将物体的坐标改成物体和灯光构成的向量。这是为什么?这里我们要提到齐次坐标,在齐次空间中我们认为(1, 3, 2, 1 )和 ( 2, 6, 4, 2 )是同一点。他们的代表是(
1, 3, 2, 1 ),也就是我们将w不等于1的都通过所以分量除以w来使得w等于1.但当w=0时,我们认为( 1, 3, 2, 0 )是一个点,它离原点无限远,并且它和原点的连线与向量( 1, 3, 2 )方向一致。一开始可能会认为为什么不在原来的点的基础上沿灯光到像素方向进行平移呢?其实当我们采用无穷远的方案时,就不必再原来点的基础上了,我们可以忽略,而直接在原点的基础上平移,仔细想想,无穷远的距离与有限距离比起来,有限距离总是可以忽略的,因为它占的比率可以无限放小,以至于忽略。

 

最后一点小领会就是在想实现颜色叠加时,如一个白灯照亮一个场景,如果再添加一个绿灯,场景需要再添加上绿灯引起的相应的颜色。在白灯已经对场景处理一次之后,绿灯的处理仍然要用到白灯建立起来的zbuffer,为了让绿灯处理的场景能够通过zbuffer,我们把ZFunc改为小于并且等于。关键是等于,可以是的绿灯继续使用zbuffer,而不用清除。

 

基本上这是索引ShadowVolume中比较难理解的地方了。我通过完全手动重新这个sample比较全面的理解里面的细节。如果有问题可以联系我。

时间: 2024-10-01 19:25:16

ShadowVolume DX9的相关文章

vc6 0-请教一下安装了DX9,VC6.0不显示函数的问题

问题描述 请教一下安装了DX9,VC6.0不显示函数的问题 请教一下各位大神,我在电脑上安装了DX9 sdk之后,在目录中把include和lib都包含进去了,但是在写的过程中像打"lpD3DDevice->"后没有显示函数的列表,也没有参数提示,这是声明的"LPDIRECT3DDEVICE9"的. 但是声明的"LPDIRECT3DDEVICE"设备后,"lpD3DDevice->"就有函数显示了. 请问一下怎么让

ShadowMap DX9

 ShadowMap基本的思想很简单,首先从聚光灯角度对场景建立并保存场景深度.然后在正常渲染场景中,比较每个渲染点到灯的距离值(或者说到灯的深度值)是否比对应的已经建立在场景深度中的值要大,也就是说要远,如果远证明从当前视点观察的此点在灯角度中看不见,所以该渲染点处于阴影中,否则,不然.   首先分析一下ShadowMap的优劣: 优点: ShadowMap只适合较近距离的阴影投射,由于32位浮点数的精度有限,所以在较远距离下,会将在阴影边界附近出现错误现象.一种是隐隐约约的阴影(即阴影中带有

错误信息-编译DX9程序出现奇怪的错误,请大牛帮忙解决,谢谢

问题描述 编译DX9程序出现奇怪的错误,请大牛帮忙解决,谢谢 1>g:directx 2007included3dx9math.h(787) : error C2143: syntax error : missing ',' before '*' 1>g:directx 2007included3dx9math.h(792) : error C2143: syntax error : missing ',' before '*' 1>g:directx 2007included3dx9m

ParallaxOcclusionMapping( POM ) DX9

ParallaxOcclusionMapping(后面成为POM)是一个不错的高级技术,在我看来它是至今让我印象最深刻的技术.与其说是视差,不如说准确的视线与高度图交点算法.在<Real-time Rendering>中也见过他的前身-ParallaxMapping,但是POM的精确度更高,对于斜视效果也很不错,这将让它在未来的重要技术中占有一席之地.闲话少说,还是重在实质技术.   在DX9的samples中,由ATI提高的POM案例,确实是一个不错的实践机会.看过2006的Dynamic

HDRPipeline DX9

 HDR这个词汇在我看过的书或资料中多次出现,从<Real-time Rendering>到SDK里面的偶尔出现,一直对其是一种莫名的感觉,HDR是什么,High Dynamic Range,范围很广,为什么要HDR呢?因为了更好的画面.这些很浅显的认识让我一直云里雾里.终于在DX9的sample中有这么个简单的HDR教学实例,确实让我了解很多.在网上看到3d本身渲染的未经过HDR处理的图片和经过HDR处理过的图片比较起来,HDR所带来的图片确实让我折服.因为HDR处理后的图片让人感到身临其境

DX9.0与opengl2.0的转换

问题描述 用DX9.0及HLSL写的地形渲染算法对应转换为opengl2.0来实现,有没有高手从事过相关方面的开发经验或相关资料,望不吝赐教... 解决方案 解决方案二:求解啊....解决方案三:使用ANGLE,你可以搜索ANGLE项目.

SkinnedMesh DX9

本想学习PRT技术,但是觉得这个技术太高级,而且就中国现在的技术来看,还未到这个程度.但是PRT技术一定要学,一定要掌握,才能不致于落后国际水平太多.这几天学习了一下骨骼动画.以前记得参加齐鲁软件大赛的时候,用Ogre很简单的就实现了骨骼动画.现在终于可以自己在DX基础上亲手完成这个3d游戏中最重要的技术.   骨骼动画中有许多我们需要注意的.简单屡一下骨骼动画中需要知道的基本知识点. 首先我们需要一个骨架.这些骨架中的骨骼有父子关系,有兄弟关系.父关节的运动是会带动子关节的.就像我们的上臂动会

MultiAnim DX9

这个案例比SkinnedMesh多的我觉得只是与骨骼动画更多的接口的认识.   MultiAnim主要的知识是: 在D3D中,一个动画控制接口有多个轨道,每个轨道上都独立的控制.我们可以控制轨道是否启用,速度,权重,优先级别.然后同个优先级别的每个轨道的动画会按对应的权重进行混合,最后不同优先级别再度混合.   这种独立有条理的结构同时也可以实现一个动画平滑过渡到另一个动画.   这些在我上传的d3dx_skinnedmesh.pdf都提及到了,而且系统全面.这里只总结MultiAnim中给我更

Post Process DX9

这个案例是一个大杂烩,它把很多常用的操作以单独模块的形式进行组装以实现一定的效果.这里面最重要的是所有的这些技术都是后处理技术,也就是在正常渲染完成后对生成的场景帧(或者说纹理,图片)进行加工处理.Post Process与以往案例最大的不同在于将物体的几何信息分别存贮在不同的渲染表面中.这样做的好处,在后处理中仍然能得到需要各种的信息.另外后处理的一个强大之处在于,当场景有多个或多种灯光时,我们不用对物体一一采用各种光照模型,因为很多像素对应的fragment(将要写入这个像素的某个物体小碎片