Hardware Skinning Support

- Supports GL, D3D9 & D3D11
- Extends vertex formats & shadergen to support blend indices and weights
- Adds basic support for using 4x3 matrices for shader constants
- Supports software fallback
This commit is contained in:
James Urquhart 2015-01-10 19:41:25 +00:00
parent 507c239a87
commit 3496c549b5
72 changed files with 2533 additions and 1327 deletions

View file

@ -368,8 +368,9 @@ void TSShapeInstance::renderDebugNormals( F32 normalScalar, S32 dl )
PrimBuild::begin( GFXLineList, 2 * numNrms );
for ( U32 n = 0; n < numNrms; n++ )
{
Point3F norm = mesh->mVertexData[n].normal();
Point3F vert = mesh->mVertexData[n].vert();
const TSMesh::__TSMeshVertexBase &v = mesh->mVertexData.getBase(n);
Point3F norm = v.normal();
Point3F vert = v.vert();
meshMat.mulP( vert );
meshMat.mulV( norm );
@ -527,17 +528,65 @@ void TSShapeInstance::render( const TSRenderState &rdata, S32 dl, F32 intraDL )
return;
}
// run through the meshes
S32 start = rdata.isNoRenderNonTranslucent() ? mShape->subShapeFirstTranslucentObject[ss] : mShape->subShapeFirstObject[ss];
S32 end = rdata.isNoRenderTranslucent() ? mShape->subShapeFirstTranslucentObject[ss] : mShape->subShapeFirstObject[ss] + mShape->subShapeNumObjects[ss];
S32 end = rdata.isNoRenderTranslucent() ? mShape->subShapeFirstTranslucentObject[ss] : mShape->subShapeFirstObject[ss] + mShape->subShapeNumObjects[ss];
TSVertexBufferHandle *realBuffer;
if (TSShape::smUseHardwareSkinning)
{
// For hardware skinning, just using the buffer associated with the shape will work fine
realBuffer = &mShape->mShapeVertexBuffer;
}
else
{
// For software skinning, we need to update our own buffer each frame
realBuffer = &mSoftwareVertexBuffer;
if (realBuffer->getPointer() == NULL)
{
mShape->getVertexBuffer(*realBuffer, GFXBufferTypeDynamic);
}
if (bufferNeedsUpdate(od, start, end))
{
U8 *buffer = realBuffer->lock();
if (!buffer)
return;
// Base vertex data
dMemcpy(buffer, mShape->mShapeVertexData.base, mShape->mShapeVertexData.size);
// Apply skinned verts (where applicable)
for (i = start; i < end; i++)
{
mMeshObjects[i].updateVertexBuffer(od, buffer);
}
realBuffer->unlock();
}
}
// run through the meshes
for (i=start; i<end; i++)
{
TSRenderState objState = rdata;
// following line is handy for debugging, to see what part of the shape that it is rendering
// const char *name = mShape->names[ mMeshObjects[i].object->nameIndex ];
mMeshObjects[i].render( od, mMaterialList, rdata, mAlphaAlways ? mAlphaAlwaysValue : 1.0f );
const char *name = mShape->names[ mMeshObjects[i].object->nameIndex ];
mMeshObjects[i].render( od, *realBuffer, mMaterialList, objState, mAlphaAlways ? mAlphaAlwaysValue : 1.0f, name );
}
}
bool TSShapeInstance::bufferNeedsUpdate(S32 objectDetail, S32 start, S32 end)
{
// run through the meshes
for (U32 i = start; i<end; i++)
{
if (mMeshObjects[i].bufferNeedsUpdate(objectDetail))
return true;
}
return false;
}
void TSShapeInstance::setCurrentDetail( S32 dl, F32 intraDL )
{
PROFILE_SCOPE( TSShapeInstance_setCurrentDetail );
@ -711,15 +760,27 @@ S32 TSShapeInstance::setDetailFromScreenError( F32 errorTolerance )
// Object (MeshObjectInstance & PluginObjectInstance) render methods
//-------------------------------------------------------------------------------------
void TSShapeInstance::ObjectInstance::render( S32, TSMaterialList *, const TSRenderState &rdata, F32 alpha )
void TSShapeInstance::ObjectInstance::render( S32, TSVertexBufferHandle &vb, TSMaterialList *, TSRenderState &rdata, F32 alpha, const char *meshName )
{
AssertFatal(0,"TSShapeInstance::ObjectInstance::render: no default render method.");
}
void TSShapeInstance::ObjectInstance::updateVertexBuffer( S32 objectDetail, U8 *buffer )
{
AssertFatal(0, "TSShapeInstance::ObjectInstance::updateVertexBuffer: no default vertex buffer update method.");
}
bool TSShapeInstance::ObjectInstance::bufferNeedsUpdate( S32 objectDetai )
{
return false;
}
void TSShapeInstance::MeshObjectInstance::render( S32 objectDetail,
TSVertexBufferHandle &vb,
TSMaterialList *materials,
const TSRenderState &rdata,
F32 alpha )
TSRenderState &rdata,
F32 alpha,
const char *meshName )
{
PROFILE_SCOPE( TSShapeInstance_MeshObjectInstance_render );
@ -751,12 +812,22 @@ void TSShapeInstance::MeshObjectInstance::render( S32 objectDetail,
const U32 currTime = Sim::getCurrentTime();
bool isSkinDirty = currTime != mLastTime;
// Update active transform list for bones for GPU skinning
if ( mesh->getMeshType() == TSMesh::SkinMeshType )
{
if (isSkinDirty)
{
static_cast<TSSkinMesh*>(mesh)->updateSkinBones(*mTransforms, mActiveTransforms);
}
rdata.setNodeTransforms(mActiveTransforms.address(), mActiveTransforms.size());
}
mesh->render( materials,
rdata,
isSkinDirty,
*mTransforms,
mVertexBuffer,
mPrimitiveBuffer );
vb,
meshName );
// Update the last render time.
mLastTime = currTime;
@ -764,6 +835,33 @@ void TSShapeInstance::MeshObjectInstance::render( S32 objectDetail,
GFX->popWorldMatrix();
}
void TSShapeInstance::MeshObjectInstance::updateVertexBuffer(S32 objectDetail, U8 *buffer)
{
PROFILE_SCOPE(TSShapeInstance_MeshObjectInstance_updateVertexBuffer);
if (forceHidden || ((visible) <= 0.01f))
return;
TSMesh *mesh = getMesh(objectDetail);
if (!mesh)
return;
// Update the buffer here
if (mesh->getMeshType() == TSMesh::SkinMeshType)
{
static_cast<TSSkinMesh*>(mesh)->updateSkinBuffer(*mTransforms, buffer);
}
mLastTime = Sim::getCurrentTime();
}
bool TSShapeInstance::MeshObjectInstance::bufferNeedsUpdate( S32 objectDetail )
{
TSMesh *mesh = getMesh(objectDetail);
const U32 currTime = Sim::getCurrentTime();
return mesh && mesh->getMeshType() == TSMesh::SkinMeshType && currTime != mLastTime;
}
TSShapeInstance::MeshObjectInstance::MeshObjectInstance()
: meshList(0), object(0), frame(0), matFrame(0),
visible(1.0f), forceHidden(false), mLastTime( 0 )