关于ShadowVolume的改进

Irrlicht引擎(1.3版本)中的shadow volume里面重复绘制了很多无用的阴影体。这里提出一种算法,减少绘制的数量。

给定光照方向light,遍历所有三角形创建Edge信息(一条Edge包含两个端点的索引,两个连接的面)。

假定我们找到了边1是一条真正的边缘(连接的两个面一个背向一个面向光源),并记录背向光源的面0(红色的0),从边1(边1是面0的边)开始(当前边为1),顺时针增加变为边2,找到边2对应的另外一个三角形面1,计算出面1对应 边2 的边4,设为当前边为边4,计算面1法向与光源的点击,得出面1在背面,继续上面的步骤(当前边为4,当前的面为1)。有  边:4->5(顺时针增加)->7 面:1->2

有 边:7->8(顺指针旋转)->10 面:2->3

 

现在面为3,边为10.继续旋转边得到10->11,11对应的另外一个面为4,4中和边11对应的是边13,更新当前边为13,计算面4是面向光源的(点积为负)。我们回溯当前边13->11,并将边11(边13也是一样的)加入“边缘”中。(此时就有了两条边1,11)

此时当前面还是3,当前边11,这和最开始面为0,边为1的初始情况相同,重复即可得到所有的边缘。

<如果面4是不存在的,直接将边11加入边缘,同时不改变当前面,进行旋转11->12>

 

这个方法的优点:通过这个方法可以直接构成一个连接着个圆圈,不用排序,

这样就很容易去解决封口问题(都可以弄成一个三角扇了)。

 

通过这个方法能够将fps从100(Irrlicht的方法)提升到150(使用一个三角面片特别多的物体时,15000+的索引);

送入显卡的三角形数量从40608减少到了1488,真是震惊。

box效果图

 

意义:如果要寻找到相邻/连的边,简单的做法是顶点数据中添加边的记录譬如:

struct Vertex

{

  float x,y,z;

  float u,v;

  float normalX,normalY,normalZ;

  vector<Edge> Edges;

}

每一个顶点都需要一个Edge的数组,但是实际情况下,每一个顶点对应的边都是不恒定的。有的只有三个,有的多达9个。这个vector就显得十分臃肿。这里只需要计算所有的边数据,这个结构稳定,就可以找出下一条边,只是不那么直观。

 

 

缺点:1 这个方法实现起来真心问题多,模型里面的数据排布直接把人搞疯掉。模型数据的冗余,导致大部分的优化措施无法起作用,并且显示不正常在Debug了很久才发现是模型的问题。

2 虽然理论上可以处理缺角(不封闭)的模型,测试也成功了。但是处理DxSDK 里面的dwarf.x模型却意外的无法成功,所以还是只能说,这个算法限于封闭模型使用。

3 由于模型的缺陷使得优化无法使用,所以预处理步骤真心慢,特别慢。

 

基于上述原因:

 

 这个方法不去使用。

 

思考:ShadowVolume方法的主要问题就是阴影体的生成,上面虽然提到了快速找到边缘,但是实际上可行的方法确实另外一种(我想到的):

1 遍历所有三角形,记录每条边缘的访问次数(背面的三角形给每条边加1),将其对应的背面三角形加入渲染列表(封口)

2 只有真正的边缘(光照)访问次数为1,(当然也有空洞的边缘可以,也将其加入,但是不会影响最终结果),

3 对于这样的边缘,进行拉伸,得到阴影体。

 

这么看来,生成阴影体的方法其实很简单,上面的工作只是为了能够根据简单的拓扑信息得到对应的边而已。权当做一个尝试。

posted @ 2015-01-28 16:14  kalluwa  阅读(422)  评论(0编辑  收藏  举报