- Initial GLTF Animation Implementation. For now only supports boneless TRS animations without scale.

![only works with r_UseGpuSkinning 0]!
- Writes bmd5anim for each animation. its not perfect yet but, rot + trans looks good.
- Model tag supports gltf Animations. Indexed the same way as meshes.
- Enabled weights and bone index in ConvertFromMeshGltf
This commit is contained in:
HarrievG 2022-07-10 21:09:25 +02:00
parent 833f112f4e
commit edf657f50d
10 changed files with 1314 additions and 237 deletions

View file

@ -633,7 +633,7 @@ bool idCollisionModelManagerLocal::LoadCollisionModelFile( const char* name, uns
int id;
idStr tmp;
idStr file = fileName;
gltfManager::ExtractMeshIdentifier( file, id, tmp );
gltfManager::ExtractIdentifier( file, id, tmp );
currentTimeStamp = fileSystem->GetTimestamp( file );
}

View file

@ -4574,7 +4574,7 @@ cmHandle_t idCollisionModelManagerLocal::LoadModel( const char* modelName, const
int id;
idStr tmp;
idStr file = modelName;
gltfManager::ExtractMeshIdentifier( file, id, tmp );
gltfManager::ExtractIdentifier( file, id, tmp );
sourceTimeStamp = fileSystem->GetTimestamp( file );
}

View file

@ -31,6 +31,8 @@ If you have questions concerning this license or the applicable additional terms
#include "../Game_local.h"
//should go before release?
#include "renderer/Model_gltf.h"
idCVar binaryLoadAnim( "binaryLoadAnim", "1", 0, "enable binary load/write of idMD5Anim" );
@ -177,18 +179,47 @@ idMD5Anim::LoadAnim
*/
bool idMD5Anim::LoadAnim( const char* filename )
{
idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
idToken token;
idStr extension;
idStr filenameStr = idStr( filename );
filenameStr.ExtractFileExtension( extension );
idStr generatedFileName = "generated/anim/";
generatedFileName.AppendPath( filename );
generatedFileName.SetFileExtension( ".bMD5anim" );
// Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it
ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( filename );
idStr gltfFileName = idStr( filename );
int gltfAnimId = -1;
idStr gltfAnimName;
// Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it
ID_TIME_T sourceTimeStamp;
bool isGLTF = ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 ) ;
if( isGLTF )
{
gltfManager::ExtractIdentifier( gltfFileName, gltfAnimId, gltfAnimName );
sourceTimeStamp = fileSystem->GetTimestamp( gltfFileName );
}
else
{
sourceTimeStamp = fileSystem->GetTimestamp( filename );
}
idFile* fileptr = fileSystem->OpenFileReadMemory( generatedFileName );
bool doWrite = false;
if( fileptr == nullptr && isGLTF )
{
fileptr = idRenderModelGLTF::GetAnimBin( filenameStr , sourceTimeStamp );
doWrite = fileptr != nullptr;
}
idFileLocal file( fileptr );
idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
if( binaryLoadAnim.GetBool() && LoadBinary( file, sourceTimeStamp ) )
{
name = filename;
@ -197,6 +228,14 @@ bool idMD5Anim::LoadAnim( const char* filename )
// for resource gathering write this anim to the preload file for this map
fileSystem->AddAnimPreload( name );
}
if( doWrite && binaryLoadAnim.GetBool( ) )
{
idLib::Printf( "Writing %s\n", generatedFileName.c_str( ) );
fileptr->Seek( 0, FS_SEEK_SET );
idFile_Memory* memFile = static_cast<idFile_Memory*>( fileptr );
fileSystem->WriteFile( generatedFileName, memFile->GetDataPtr(), memFile->GetAllocated(), "fs_basepath" );
}
return true;
}

View file

@ -3361,7 +3361,7 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi
// get the number of joints
num = modelHandle->NumJoints();
if( !num )
if( !num && !isGltf )
{
src.Warning( "Model '%s' has no joints", filename.c_str() );
}

View file

@ -204,30 +204,50 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p
}
break;
}
//case gltfMesh_Primitive_Attribute::Type::Weight:
//{
// for ( int i = 0; i < attrAcc->count; i++ ) {
// bin.Read( ( void * ) ( &vtxData[i].weight.x ), attrAcc->typeSize );
// bin.Read( ( void * ) ( &vtxData[i].weight.y ), attrAcc->typeSize );
// bin.Read( ( void * ) ( &vtxData[i].weight.z ), attrAcc->typeSize );
// bin.Read( ( void * ) ( &vtxData[i].weight.w ), attrAcc->typeSize );
// if ( attrBv->byteStride )
// bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR );
// }
// break;
//}
//case gltfMesh_Primitive_Attribute::Type::Indices:
//{
// for ( int i = 0; i < attrAcc->count; i++ ) {
// bin.Read( ( void * ) ( &vtxData[i].boneIndex.x ), attrAcc->typeSize );
// bin.Read( ( void * ) ( &vtxData[i].boneIndex.y ), attrAcc->typeSize );
// bin.Read( ( void * ) ( &vtxData[i].boneIndex.z ), attrAcc->typeSize );
// bin.Read( ( void * ) ( &vtxData[i].boneIndex.w ), attrAcc->typeSize );
// if ( attrBv->byteStride )
// bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR );
// }
// break;
//}
case gltfMesh_Primitive_Attribute::Type::Weight:
{
idVec4 vec;
for( int i = 0; i < attrAcc->count; i++ )
{
bin.Read( ( void* )( &vec.x ), attrAcc->typeSize );
bin.Read( ( void* )( &vec.y ), attrAcc->typeSize );
bin.Read( ( void* )( &vec.z ), attrAcc->typeSize );
bin.Read( ( void* )( &vec.w ), attrAcc->typeSize );
if( attrBv->byteStride )
{
bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR );
}
mesh->verts[i].color2[0] = vec.x;
mesh->verts[i].color2[1] = vec.y;
mesh->verts[i].color2[2] = vec.z;
mesh->verts[i].color2[3] = vec.w;
}
break;
}
case gltfMesh_Primitive_Attribute::Type::Indices:
{
idVec4 vec;
for( int i = 0; i < attrAcc->count; i++ )
{
bin.Read( ( void* )( &vec.x ), attrAcc->typeSize );
bin.Read( ( void* )( &vec.y ), attrAcc->typeSize );
bin.Read( ( void* )( &vec.z ), attrAcc->typeSize );
bin.Read( ( void* )( &vec.w ), attrAcc->typeSize );
if( attrBv->byteStride )
{
bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR );
}
mesh->verts[i].color[0] = vec.x;
mesh->verts[i].color[1] = vec.y;
mesh->verts[i].color[2] = vec.z;
mesh->verts[i].color[3] = vec.w;
}
break;
}
}
}

View file

@ -2319,38 +2319,38 @@ CONSOLE_COMMAND_COMPILE( LoadGLTF, "Loads an .gltf or .glb file", idCmdSystem::A
// not dots allowed in [%s]!
// [filename].[%i|%s].[gltf/glb]
bool gltfManager::ExtractMeshIdentifier( idStr& filename, int& meshId, idStr& meshName )
bool gltfManager::ExtractIdentifier( idStr& filename, int& id, idStr& name )
{
idStr extension;
idStr meshStr;
idStr targetStr;
filename.ExtractFileExtension( extension );
idStr file = filename;
file = file.StripFileExtension();
file.ExtractFileExtension( meshStr );
file.ExtractFileExtension( targetStr );
if( !extension.Length() )
{
idLib::Warning( "no gltf mesh identifier" );
idLib::Warning( "no gltf identifier" );
return false;
}
if( meshStr.Length() )
if( targetStr.Length() )
{
filename = file.Left( file.Length() - meshStr.Length() - 1 ) + "." + extension;
filename = file.Left( file.Length() - targetStr.Length() - 1 ) + "." + extension;
idParser parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
parser.LoadMemory( meshStr.c_str(), meshStr.Size(), "model:GltfmeshID" );
parser.LoadMemory( targetStr.c_str(), targetStr.Size(), "model:GltfID" );
idToken token;
if( parser.ExpectAnyToken( &token ) )
{
if( ( token.type == TT_NUMBER ) && ( token.subtype & TT_INTEGER ) )
{
meshId = token.GetIntValue();
id = token.GetIntValue();
}
else if( token.type == TT_NAME )
{
meshName = token;
name = token;
}
else
{

View file

@ -349,7 +349,7 @@ private:
class gltfManager
{
public:
static bool ExtractMeshIdentifier( idStr& filename , int& meshId, idStr& meshName );
static bool ExtractIdentifier( idStr& filename , int& id, idStr& name );
};
extern GLTF_Parser* gltfParser;

View file

@ -943,6 +943,20 @@ public:
return nullptr;
}
int GetNodeIndex( gltfNode* node )
{
int index = -1;
for( auto* node : nodes )
{
index++;
if( node == node )
{
return index;
}
}
return -1;
}
bool HasAnimation( int nodeID )
{
for( auto anim : animations )
@ -958,6 +972,18 @@ public:
return false;
}
gltfAnimation* GetAnimation( idStr animName )
{
for( auto anim : animations )
{
if( anim->name == animName )
{
return anim;
}
}
return nullptr;
}
int GetSceneId( idStr sceneName ) const
{
for( int i = 0; i < scenes.Num(); i++ )
@ -970,6 +996,41 @@ public:
return -1;
}
idList<int> GetChannelIds( gltfAnimation* anim , gltfNode* node )
{
idList<int> result;
int channelIdx = 0;
for( auto channel : anim->channels )
{
if( channel->target.node >= 0 && nodes[channel->target.node] == node )
{
result.Append( channelIdx );
break;
}
channelIdx++;
}
return result;
}
idList<int> GetAnimationIds( gltfNode* node )
{
idList<int> result;
int animIdx = 0;
for( auto anim : animations )
{
for( auto channel : anim->channels )
{
if( channel->target.node >= 0 && nodes[channel->target.node] == node )
{
result.Append( animIdx );
break;
}
}
animIdx++;
}
return result;
}
idMat4 GetViewMatrix( int camId ) const
{
//if (cameraManager->HasOverideID(camId) )

File diff suppressed because it is too large Load diff

View file

@ -29,19 +29,6 @@ If you have questions concerning this license or the applicable additional terms
#pragma once
#include "Model_local.h"
class idGltfMesh
{
public:
idGltfMesh( ) {};
idGltfMesh( gltfMesh* _mesh, gltfData* _data );
private:
gltfMesh* mesh;
gltfData* data;
idMD5Mesh md5Mesh;
};
class idRenderModelGLTF : public idRenderModelStatic
{
public:
@ -67,20 +54,30 @@ public:
{
return true;
}
void MakeMD5Mesh() ;
static idFile_Memory* GetAnimBin( idStr animName, const ID_TIME_T sourceTimeStamp );
private:
void ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData* data );
void UpdateSurface( const struct renderEntity_s* ent, idMat4 trans, modelSurface_t* surf );
void UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf );
void UpdateMd5Joints();
int rootID;
gltfData* data;
gltfNode* root;
bool fileExclusive;
bool hasAnimations;
idList<int> animIds;
idList<idGltfMesh, TAG_MODEL> meshes;
float maxJointVertDist; // maximum distance a vertex is separated from a joint
idList<int, TAG_MODEL> animIds;
idList<int, TAG_MODEL> bones;
dynamicModel_t model_state;
idMat4 prevTrans;
idList<gltfNode*, TAG_MODEL> SkeletonNodes;
idList<idMD5Joint, TAG_MODEL> md5joints;
idList<idJointQuat, TAG_MODEL> defaultPose;
idList<idJointMat, TAG_MODEL> invertedDefaultPose;
idList<idMD5Mesh, TAG_MODEL> meshes;
deformInfo_t* deformInfo;
MapPolygonMesh* mesh;
private:
void DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view );
};