DirectX9.0C直接支持Geometry Instance,通过D3DDECLUSAGE_TEXCOORD多层纹理坐标流,将Instance Data数据传送到GPU,技巧在于:
pd3dDevice->SetStreamSourceFreq(0, (D3DSTREAMSOURCE_INDEXEDDATA | g_numInstancesToDraw));
pd3dDevice->SetStreamSource(0, g_VB_Geometry, 0, D3DXGetDeclVertexSize(g_VBDecl_Geometry, 0));
pd3dDevice->SetStreamSourceFreq(1, (D3DSTREAMSOURCE_INSTANCEDATA | 1));
pd3dDevice->SetStreamSource(1, g_VB_InstanceData, 0, D3DXGetDeclVertexSize( g_VBDecl_InstanceData, 1));
Stream1中的顶点数据,每g_numInstancesToDraw个顶点处理后递进一个,相当于每Instance递进一次.在HLSL中将Stream1中的数据流还原出来.
OpenGL当前不直接支持Geometry Instance,但是注意到
1.OpenGL的glDrawElements簇函数的消耗比DX的DrawIndexedPrimitives小得多.
2.OpenGL有一项DirectX所没有的能力,设置当前全局顶点数据,如glColor3f,glTexCoord,glMultiTexCoord,而且此类函数的单个调用在Driver和hardware上的消耗都极小,所以可以用glMultiTexCoord传递顶点数据到shader,而不是使用glUniformMatrix4fvARB或glLoadMatrix传递变换矩阵,此类设置GPU寄存器的函数,或者说是改变Vertex shader当前的全局处理状态的函数,很显然将等待当前GPU正在执行的Vertex process完成后才能返回,CPU将等待GPU.
The technique does not scale well to complex mesh rendering techniques like skinning; there
are not enough vertex attributes to store all of the bone transforms for each instance.
但,无论Directx9.0c或OpenGL2.1都无法传递几十个骨骼矩阵这么庞大的顶点数据单位格式(注意是一个顶点数据单位格式,OpenGL没有那么多层的glMultiTexCoord, DirectX没有那么大的顶点声明能容纳几十个矩阵),所以都无法完成带骨骼动画的Geometry Instance,只能是静态物体,或使用CPU作骨骼计算. DX10好像可以,没有显卡,没实践过.
CPU和GPU是并行结构,若使得两者完全并行运行,效率将最大化.若一方为了线性逻辑而不得不去等待另一方,效率将降低,这就好像两个线程间需要同步的数据或逻辑越多,效率就越低下.
Reference:
http://developer.download.nvidia.com/SDK/9.5/Samples/DEMOS/Direct3D9/src/HLSL_Instancing/docs/HLSL_Instancing.pdf
http://developer.download.nvidia.com/SDK/9.5/Samples/DEMOS/OpenGL/src/glsl_pseudo_instancing/docs/glsl_pseudo_instancing.pdf