mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-12 19:31:41 +00:00
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:
parent
507c239a87
commit
3496c549b5
72 changed files with 2533 additions and 1327 deletions
|
|
@ -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 )
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue