1、InstanceBatchHW 简介
InstanceBatchHW 全名 InstanceBatch hardware 即硬件缓存存储批次中entity信息, 创建同一个批次模型时,将每个模型的节点仿射矩阵(3×4或4×4)存储到顶点纹理缓存中(矩阵纹理缓存), 最后GPU利用该矩阵更新顶点位置。
注:InstanceBatchHW 不支持entity动画。
2、InstanceBatchHW 创建
- InstanceBatchHW 基本信息的创建
- InstanceBatchHW 设置顶点缓存
先复值原Entity中的顶点数据到mRenderOperation对象里,删除该动画数据(删除顶点类型:VES_BLEND_WEIGHTS、VES_BLEND_INDICES和对应的顶点数据),然后声明至少3个顶点纹理类型(如果附加自定义变量需要创建更多顶点类型),最后创建顶点数据和顶点索引不需要修改直接拷贝。
如下代码:
void InstanceBatchHW::setupVertices( const SubMesh* baseSubMesh )
{
mRenderOperation.vertexData = baseSubMesh->vertexData->clone();
mRemoveOwnVertexData = true; //Raise flag to remove our own vertex data in the end (not always needed)
VertexData *thisVertexData = mRenderOperation.vertexData;
//No skeletal animation support in this technique, sorry
removeBlendData();
//Modify the declaration so it contains an extra source, where we can put the per instance data
size_t offset = 0;
unsigned short nextTexCoord = thisVertexData->vertexDeclaration->getNextFreeTextureCoordinate();
const unsigned short newSource = thisVertexData->vertexDeclaration->getMaxSource() + 1;
for( unsigned char i=0; i<3 + mCreator->getNumCustomParams(); ++i )
{
thisVertexData->vertexDeclaration->addElement( newSource, offset, VET_FLOAT4,
VES_TEXTURE_COORDINATES, nextTexCoord++ );
offset = thisVertexData->vertexDeclaration->getVertexSize( newSource );
}
//Create the vertex buffer containing per instance data
HardwareVertexBufferSharedPtr vertexBuffer =
HardwareBufferManager::getSingleton().createVertexBuffer(
thisVertexData->vertexDeclaration->getVertexSize(newSource),
mInstancesPerBatch,
HardwareBuffer::HBU_STATIC_WRITE_ONLY );
thisVertexData->vertexBufferBinding->setBinding( newSource, vertexBuffer );
vertexBuffer->setIsInstanceData( true );
vertexBuffer->setInstanceDataStepRate( 1 );
}
3、InstanceBatchHW 写入矩阵纹理数据
- 获取每个entity对象的节点的转换矩阵(3×4),将矩阵信息写到mRenderOperation对象里上一步创建的顶点纹理数据中。
如下代码:
size_t InstanceBatchHW::updateVertexBuffer( Camera *currentCamera )
{
size_t retVal = 0;
//Now lock the vertex buffer and copy the 4x3 matrices, only those who need it!
const Oushort bufferIdx = Oushort(mRenderOperation.vertexData->vertexBufferBinding->getBufferCount()-1);
float *pDest = static_cast<float*>(mRenderOperation.vertexData->vertexBufferBinding->
getBuffer(bufferIdx)->lock( HardwareBuffer::HBL_DISCARD ));
InstancedEntityVec::const_iterator itor = mInstancedEntities.begin();
InstancedEntityVec::const_iterator end = mInstancedEntities.end();
unsigned char numCustomParams = mCreator->getNumCustomParams();
size_t customParamIdx = 0;
while( itor != end )
{
//Cull on an individual basis, the less entities are visible, the less instances we draw.
//No need to use null matrices at all!
if( (*itor)->findVisible( currentCamera ) )
{
const size_t floatsWritten = (*itor)->getTransforms3x4( pDest );
if( mManager->getCameraRelativeRendering() )
makeMatrixCameraRelative3x4( pDest, floatsWritten );
pDest += floatsWritten;
//Write custom parameters, if any
for( unsigned char i=0; i<numCustomParams; ++i )
{
*pDest++ = mCustomParams[customParamIdx+i].x;
*pDest++ = mCustomParams[customParamIdx+i].y;
*pDest++ = mCustomParams[customParamIdx+i].z;
*pDest++ = mCustomParams[customParamIdx+i].w;
}
++retVal;
}
++itor;
customParamIdx += numCustomParams;
}
mRenderOperation.vertexData->vertexBufferBinding->getBuffer(bufferIdx)->unlock();
return retVal;
}
4、InstanceBatchHW GPU顶点着色器数据更新
- 代码注释详解 如下代码:
#version 120
//Vertex input
attribute vec4 vertex; //顶点数据
attribute vec3 normal; //法向量
attribute vec4 uv0; //纹理坐标
attribute vec4 uv1; //矩阵纹理第一行数据
attribute vec4 uv2; //矩阵纹理第二行数据
attribute vec4 uv3; //矩阵纹理第三行数据
attribute vec3 tangent; //自定义变量()
//Parameters
uniform mat4 viewProjMatrix;
#if (DEPTH_SHADOWCASTER || DEPTH_SHADOWRECEIVER)
uniform vec4 depthRange;
#endif
#if DEPTH_SHADOWRECEIVER
uniform mat4 texViewProjMatrix;
#endif
//Output
#if DEPTH_SHADOWCASTER
varying vec2 depth;
#else
varying vec2 _uv0;
varying vec3 oNormal;
varying vec3 oVPos;
#if DEPTH_SHADOWRECEIVER
varying vec4 oLightSpacePos;
#endif
#endif
//---------------------------------------------
//Main Vertex Shader
//---------------------------------------------
void main(void)
{
//构建纹理矩阵
mat4 worldMatrix;
worldMatrix[0] = uv1;
worldMatrix[1] = uv2;
worldMatrix[2] = uv3;
worldMatrix[3] = vec4( 0, 0, 0, 1 );
vec4 worldPos = vertex * worldMatrix;
vec3 worldNorm = normal * mat3(worldMatrix);
//Transform the position
gl_Position = viewProjMatrix * worldPos;
#if DEPTH_SHADOWCASTER
depth.x = (gl_Position.z - depthRange.x) * depthRange.w;
depth.y = depthRange.w;
#else
_uv0 = uv0.xy;
oNormal = worldNorm;
oVPos = worldPos.xyz;
#if DEPTH_SHADOWRECEIVER
oLightSpacePos = texViewProjMatrix * worldPos;
oLightSpacePos.z = (oLightSpacePos.z - depthRange.x) * depthRange.w;
#endif
#endif
}