对目前的显卡来说,把三角形提交给显卡渲染,是一个相当较慢的操作,据wloka 2003显示,1Ghz的cpu,每秒只能渲染大约10000-40000批( 像 DrawIndexedPrimitive,DrawIndexedPrimitiveUP之类的,一次调用就算一批),在更现代的cpu上面,估计这个数目也就是在30000-120000批,按每秒30帧计算,每帧能够提交的dp次数不会超过4000,所以,为了实现一个强大的渲染引擎,一定要想办法在每次dp调用时,尽可能的处理更多的三角形。其中几何体实例化渲染就是为了实现这个目的而产生的。
几何体实例化的原理是:一个3d场景中,例如一片森林,有很多树木,一般来说,这很多树木,基本上都是共用少数的几个模型数据,只是位置,大小,旋转和颜色有些差别,采用实例化渲染技术,dp次数就取决于模型数据,而不是所渲染的树木数据了。
从技术上来说,几何体实例化并不复杂, 但是要集成到引擎中,还是需要做一些工作的,本人主要从三个方面着手:
1:数据归类,将能够实例化渲染的数据归纳在一起。
2:创建教实例化所需要的顶点格式和流。
为了方便讲解,我在这里做一些假定:
在这里,模型的顶点格式为:顶点缓冲区为一个流。
const D3DVERTEXELEMENT9 g_VBDecl_Geometry[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},//位置,
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},//法线
{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},//纹理坐标
D3DDECL_END()
};
那么,实例化的顶点格式应该是,
const D3DVERTEXELEMENT9 g_VBDecl_Geometry[] =
{
//第一个顶点缓冲区流,储存静态模型的顶点数据
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},//位置,
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},//法线
{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},//纹理坐标
//第二个顶点缓冲区流,储存每个实例的世界矩阵和颜色。
{1, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
{1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2},
{1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3},
{1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4},
{1, 64, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
3:修改hlsl
float4x4 LocalToWorld;
float4x4 GetLocalToWorld(VertexInput IN)
{
#if USE_INSTANCE //如果实例化渲染,那么世界矩阵来自于顶点输入的数据
float4x4 WorldMatrix={
IN.LocalMatrix0,
IN.LocalMatrix1,
IN.LocalMatrix2,
IN.LocalMatrix3,
};
return WorldMatrix;
#else//否则,返回设置的世界矩阵。
return LocalToWorld;
#endif
}
4:填充第2个流,并且设置,渲染。
5:测试,加载了wow的一个场景,
采用实例化渲染: 458 dp ,帧率 102帧左右
不采用实例化: 963 dp, 帧率 98帧左右。
采用实例化渲染,减少了一半的dp次数,不过,帧率提升不明显,估计是当前的瓶颈还不是在这个地方导致的。
最后上图说明。呵呵: