@@ -180,7 +180,7 @@ class ModelBuilder
180180 int GltfLightIndex);
181181
182182 template <typename GltfModelType>
183- bool LoadAnimationAndSkin (const GltfModelType& GltfModel);
183+ void LoadAnimationsAndSkins (const GltfModelType& GltfModel);
184184
185185 template <typename GltfModelType>
186186 void LoadSkins (const GltfModelType& GltfModel);
@@ -305,6 +305,198 @@ auto GetGltfDataInfo(const GltfModelType& GltfModel, int AccessorId)
305305 return GltfDataInfo{GltfAccessor, pSrcData, SrcCount, SrcByteStride};
306306}
307307
308+ template <typename GltfModelType>
309+ bool AppendMorphTargetAttribute (const GltfModelType& GltfModel,
310+ int AccessorId,
311+ Uint32 VertexCount,
312+ const std::string& Semantic,
313+ MorphTarget& Target)
314+ {
315+ const auto Accessor = GltfModel.GetAccessor (AccessorId);
316+ if (Accessor.GetCount () != VertexCount)
317+ {
318+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' contains " , Accessor.GetCount (),
319+ " values, but the primitive contains " , VertexCount, " vertices" );
320+ return false ;
321+ }
322+
323+ const auto NumComponents = Accessor.GetNumComponents ();
324+ if (NumComponents <= 0 )
325+ {
326+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' has an invalid component count" );
327+ return false ;
328+ }
329+
330+ const size_t FirstValue = Target.Values .size ();
331+ const size_t ValueCount = size_t {VertexCount} * static_cast <size_t >(NumComponents);
332+ if (FirstValue > std::numeric_limits<Uint32>::max () ||
333+ ValueCount > std::numeric_limits<size_t >::max () - FirstValue)
334+ {
335+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' is too large" );
336+ return false ;
337+ }
338+
339+ Target.Values .resize (FirstValue + ValueCount, 0 .f );
340+ float * const pDst = Target.Values .data () + FirstValue;
341+
342+ const auto WriteValues = [&](const void * pSrc, Uint32 SrcStride, float * pOutput, Uint32 Count) {
343+ return VertexDataConverter::Write ({
344+ pSrc,
345+ Accessor.GetComponentType (),
346+ static_cast <Uint32>(NumComponents),
347+ SrcStride,
348+ pOutput,
349+ VT_FLOAT32 ,
350+ static_cast <Uint32>(NumComponents),
351+ static_cast <Uint32>(NumComponents) * sizeof (float ),
352+ Count,
353+ Accessor.IsNormalized (),
354+ });
355+ };
356+
357+ if (Accessor.GetBufferViewId () >= 0 )
358+ {
359+ const auto View = GltfModel.GetBufferView (Accessor.GetBufferViewId ());
360+ const auto Buffer = GltfModel.GetBuffer (View.GetBufferId ());
361+ const int ByteStride = Accessor.GetByteStride (View);
362+ const auto pSrc = Buffer.GetData (View.GetByteOffset () + Accessor.GetByteOffset ());
363+ if (ByteStride <= 0 ||
364+ !WriteValues (pSrc, static_cast <Uint32>(ByteStride), pDst, VertexCount))
365+ {
366+ LOG_ERROR_MESSAGE (" Failed to read morph target attribute '" , Semantic, " '" );
367+ Target.Values .resize (FirstValue);
368+ return false ;
369+ }
370+ }
371+ else if (!Accessor.IsSparse ())
372+ {
373+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' has no data" );
374+ Target.Values .resize (FirstValue);
375+ return false ;
376+ }
377+
378+ if (Accessor.IsSparse ())
379+ {
380+ const size_t SparseCount = Accessor.GetSparseCount ();
381+ if (SparseCount > VertexCount)
382+ {
383+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' contains too many sparse values" );
384+ Target.Values .resize (FirstValue);
385+ return false ;
386+ }
387+
388+ const auto IndicesView = GltfModel.GetBufferView (Accessor.GetSparseIndicesBufferViewId ());
389+ const auto IndicesBuffer = GltfModel.GetBuffer (IndicesView.GetBufferId ());
390+ const auto pIndices = IndicesBuffer.GetData (IndicesView.GetByteOffset () + Accessor.GetSparseIndicesByteOffset ());
391+ const auto IndexType = Accessor.GetSparseIndicesComponentType ();
392+ const auto IndexSize = GetValueSize (IndexType);
393+
394+ const auto ValuesView = GltfModel.GetBufferView (Accessor.GetSparseValuesBufferViewId ());
395+ const auto ValuesBuffer = GltfModel.GetBuffer (ValuesView.GetBufferId ());
396+ const auto pValues = ValuesBuffer.GetData (ValuesView.GetByteOffset () + Accessor.GetSparseValuesByteOffset ());
397+ const auto ValueStride = GetValueSize (Accessor.GetComponentType ()) * static_cast <Uint32>(NumComponents);
398+
399+ if (pIndices == nullptr || pValues == nullptr || IndexSize == 0 || ValueStride == 0 )
400+ {
401+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' has invalid sparse data" );
402+ Target.Values .resize (FirstValue);
403+ return false ;
404+ }
405+
406+ Uint32 PreviousIndex = 0 ;
407+ for (size_t SparseIndex = 0 ; SparseIndex < SparseCount; ++SparseIndex)
408+ {
409+ Uint32 VertexIndex = 0 ;
410+ const auto pIndex = static_cast <const Uint8*>(pIndices) + SparseIndex * IndexSize;
411+ switch (IndexType)
412+ {
413+ case VT_UINT8 :
414+ {
415+ Uint8 Index;
416+ std::memcpy (&Index, pIndex, sizeof (Index));
417+ VertexIndex = Index;
418+ break ;
419+ }
420+
421+ case VT_UINT16 :
422+ {
423+ Uint16 Index;
424+ std::memcpy (&Index, pIndex, sizeof (Index));
425+ VertexIndex = Index;
426+ break ;
427+ }
428+
429+ case VT_UINT32 :
430+ std::memcpy (&VertexIndex, pIndex, sizeof (VertexIndex));
431+ break ;
432+
433+ default :
434+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' uses an invalid sparse index type" );
435+ Target.Values .resize (FirstValue);
436+ return false ;
437+ }
438+
439+ if (VertexIndex >= VertexCount || (SparseIndex != 0 && VertexIndex <= PreviousIndex))
440+ {
441+ LOG_ERROR_MESSAGE (" Morph target attribute '" , Semantic, " ' contains invalid sparse indices" );
442+ Target.Values .resize (FirstValue);
443+ return false ;
444+ }
445+ PreviousIndex = VertexIndex;
446+
447+ const auto pSparseValue = static_cast <const Uint8*>(pValues) + SparseIndex * ValueStride;
448+ if (!WriteValues (pSparseValue,
449+ ValueStride,
450+ pDst + size_t {VertexIndex} * static_cast <size_t >(NumComponents),
451+ 1 ))
452+ {
453+ LOG_ERROR_MESSAGE (" Failed to read sparse morph target attribute '" , Semantic, " '" );
454+ Target.Values .resize (FirstValue);
455+ return false ;
456+ }
457+ }
458+ }
459+
460+ Target.Attributes .push_back (MorphTargetAttribute{
461+ Semantic,
462+ static_cast <Uint32>(FirstValue),
463+ static_cast <Uint32>(NumComponents),
464+ });
465+ return true ;
466+ }
467+
468+ template <typename GltfModelType, typename GltfPrimitiveType>
469+ bool LoadMorphTargets (const GltfModelType& GltfModel,
470+ const GltfPrimitiveType& GltfPrimitive,
471+ Uint32 VertexCount,
472+ Primitive& DstPrimitive)
473+ {
474+ const size_t TargetCount = GltfPrimitive.GetMorphTargetCount ();
475+ DstPrimitive.MorphTargets .reserve (TargetCount);
476+ for (size_t TargetIndex = 0 ; TargetIndex < TargetCount; ++TargetIndex)
477+ {
478+ const auto & Attributes = GltfPrimitive.GetMorphTarget (TargetIndex);
479+ MorphTarget Target;
480+ Target.Attributes .reserve (Attributes.size ());
481+
482+ for (const auto & Attribute : Attributes)
483+ {
484+ if (!AppendMorphTargetAttribute (GltfModel,
485+ Attribute.second ,
486+ VertexCount,
487+ Attribute.first ,
488+ Target))
489+ {
490+ DstPrimitive.MorphTargets .clear ();
491+ return false ;
492+ }
493+ }
494+
495+ DstPrimitive.MorphTargets .emplace_back (std::move (Target));
496+ }
497+ return true ;
498+ }
499+
308500template <typename GltfModelType>
309501void ModelBuilder::LoadScenes (const GltfModelType& GltfModel, int SceneIndex)
310502{
@@ -431,6 +623,16 @@ Mesh* ModelBuilder::LoadMesh(const GltfModelType& GltfModel,
431623 }
432624 m_LoadedMeshes.emplace (LoadedMeshId);
433625
626+ if (Mesh* pMesh = MeshLoader.GetLoadedMesh (LoadedMeshId))
627+ {
628+ const auto GltfMesh = GltfModel.GetMesh (GltfMeshIndex);
629+ pMesh->Name = GltfMesh.GetName ();
630+ pMesh->Weights .reserve (GltfMesh.GetWeights ().size ());
631+ for (double Weight : GltfMesh.GetWeights ())
632+ pMesh->Weights .push_back (static_cast <float >(Weight));
633+ pMesh->MorphTargetNames = GltfMesh.GetMorphTargetNames ();
634+ }
635+
434636 return MeshLoader.LoadMesh (GltfModel, GltfMeshIndex, LoadedMeshId);
435637}
436638
@@ -443,8 +645,6 @@ Mesh* MeshLoader::LoadMesh(const GltfModelType& GltfModel,
443645
444646 const auto & GltfMesh = GltfModel.GetMesh (GltfMeshIndex);
445647
446- NewMesh.Name = GltfMesh.GetName ();
447-
448648 const size_t PrimitiveCount = GltfMesh.GetPrimitiveCount ();
449649 NewMesh.Primitives .reserve (PrimitiveCount);
450650 for (size_t prim = 0 ; prim < PrimitiveCount; ++prim)
@@ -525,7 +725,7 @@ Mesh* MeshLoader::LoadMesh(const GltfModelType& GltfModel,
525725 MaterialId = m_DefaultMaterialId;
526726 }
527727
528- NewMesh.Primitives .emplace_back (
728+ Primitive& NewPrimitive = NewMesh.Primitives .emplace_back (
529729 IndexStart,
530730 IndexCount,
531731 VertexStart,
@@ -535,8 +735,11 @@ Mesh* MeshLoader::LoadMesh(const GltfModelType& GltfModel,
535735 PosMax //
536736 );
537737
738+ if (!LoadMorphTargets (GltfModel, GltfPrimitive, VertexCount, NewPrimitive))
739+ LOG_ERROR_MESSAGE (" Failed to load morph targets for mesh '" , NewMesh.Name , " ' primitive " , prim);
740+
538741 if (m_CI.PrimitiveLoadCallback )
539- m_CI.PrimitiveLoadCallback (&GltfModel.Get (), &GltfPrimitive.Get (), NewMesh. Primitives . back () );
742+ m_CI.PrimitiveLoadCallback (&GltfModel.Get (), &GltfPrimitive.Get (), NewPrimitive );
540743 }
541744
542745 NewMesh.UpdateBoundingBox ();
@@ -704,6 +907,10 @@ Node* ModelBuilder::LoadNode(const GltfModelType& GltfModel,
704907 NewNode.Matrix = float4x4::MakeMatrix (GltfNode.GetMatrix ().data ());
705908 }
706909
910+ NewNode.Weights .reserve (GltfNode.GetWeights ().size ());
911+ for (double Weight : GltfNode.GetWeights ())
912+ NewNode.Weights .push_back (static_cast <float >(Weight));
913+
707914 // Load children first
708915 NewNode.Children .reserve (GltfNode.GetChildrenIds ().size ());
709916 for (const auto ChildNodeIdx : GltfNode.GetChildrenIds ())
@@ -1032,13 +1239,6 @@ void ModelBuilder::LoadAnimations(const GltfModelType& GltfModel)
10321239 {
10331240 const auto & GltfChannel = GltfAnim.GetChannel (chnl);
10341241
1035- const auto PathType = GltfChannel.GetPathType ();
1036- if (PathType == AnimationChannel::PATH_TYPE ::WEIGHTS )
1037- {
1038- LOG_WARNING_MESSAGE (" Weights are not yet supported, skipping channel" );
1039- continue ;
1040- }
1041-
10421242 const auto SamplerIndex = GltfChannel.GetSamplerId ();
10431243 if (SamplerIndex < 0 )
10441244 continue ;
@@ -1051,31 +1251,19 @@ void ModelBuilder::LoadAnimations(const GltfModelType& GltfModel)
10511251 if (pNode == nullptr )
10521252 continue ;
10531253
1054- Anim.Channels .emplace_back (PathType , pNode, SamplerIndex);
1254+ Anim.Channels .emplace_back (GltfChannel. GetPathType () , pNode, SamplerIndex);
10551255 }
10561256 }
10571257}
10581258
10591259template <typename GltfModelType>
1060- bool ModelBuilder::LoadAnimationAndSkin (const GltfModelType& GltfModel)
1260+ void ModelBuilder::LoadAnimationsAndSkins (const GltfModelType& GltfModel)
10611261{
1062- bool UsesAnimation = false ;
1063- for (size_t i = 0 ; i < m_Model.GetNumVertexAttributes (); ++i)
1064- {
1065- const auto & Attrib = m_Model.GetVertexAttribute (i);
1066-
1067- if (strncmp (Attrib.Name , " WEIGHTS" , 7 ) == 0 ||
1068- strncmp (Attrib.Name , " JOINTS" , 6 ) == 0 )
1069- {
1070- UsesAnimation = true ;
1071- break ;
1072- }
1073- }
1262+ LoadAnimations (GltfModel);
10741263
1075- if (!UsesAnimation )
1076- return false ;
1264+ if (GltfModel. GetSkinCount () == 0 )
1265+ return ;
10771266
1078- LoadAnimations (GltfModel);
10791267 LoadSkins (GltfModel);
10801268
10811269 // Assign skins
@@ -1098,8 +1286,6 @@ bool ModelBuilder::LoadAnimationAndSkin(const GltfModelType& GltfModel)
10981286 UNEXPECTED (" Node " , i, " has no assigned skin id. This appears to be a bug." );
10991287 }
11001288 }
1101-
1102- return true ;
11031289}
11041290
11051291template <typename GltfModelType, typename MeshLoaderType>
@@ -1139,7 +1325,7 @@ void ModelBuilder::BuildModel(const GltfModelType& GltfModel,
11391325 VERIFY_EXPR (m_LoadedCameras.size () == m_Model.Cameras .size ());
11401326 VERIFY_EXPR (m_LoadedLights.size () == m_Model.Lights .size ());
11411327
1142- LoadAnimationAndSkin (GltfModel);
1328+ LoadAnimationsAndSkins (GltfModel);
11431329}
11441330
11451331class MaterialBuilder
0 commit comments