3
0

ActorAsset.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <ActorAsset.h>
  9. #include <AtomActorInstance.h>
  10. #include <EMotionFX/Source/TransformData.h>
  11. #include <EMotionFX/Source/Actor.h>
  12. #include <EMotionFX/Source/Mesh.h>
  13. #include <EMotionFX/Source/MorphSetup.h>
  14. #include <EMotionFX/Source/MorphTargetStandard.h>
  15. #include <EMotionFX/Source/SubMesh.h>
  16. #include <EMotionFX/Source/SkinningInfoVertexAttributeLayer.h>
  17. #include <MCore/Source/DualQuaternion.h>
  18. // For creating a skinned mesh from an actor
  19. #include <Atom/Feature/SkinnedMesh/SkinnedMeshInputBuffers.h>
  20. #include <Atom/RPI.Reflect/ResourcePoolAssetCreator.h>
  21. #include <Atom/RPI.Reflect/Buffer/BufferAssetCreator.h>
  22. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  23. #include <Atom/RPI.Reflect/Model/ModelAssetHelpers.h>
  24. #include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
  25. #include <Atom/RPI.Reflect/Model/ModelLodAssetCreator.h>
  26. #include <Atom/RPI.Public/Model/Model.h>
  27. #include <AzCore/Asset/AssetManager.h>
  28. #include <AzCore/base.h>
  29. #include <AzCore/Math/Aabb.h>
  30. #include <AzCore/Math/PackedVector3.h>
  31. #include <AzCore/Math/Transform.h>
  32. #include <AzCore/Math/Matrix3x4.h>
  33. #include <AzCore/Math/MathUtils.h>
  34. #include <AzCore/Component/Entity.h>
  35. #include <inttypes.h>
  36. // Copied from ModelAssetBuilderComponent.cpp
  37. namespace
  38. {
  39. const uint32_t LinearSkinningFloatsPerBone = 12;
  40. const uint32_t DualQuaternionSkinningFloatsPerBone = 8;
  41. }
  42. namespace AZ
  43. {
  44. namespace Render
  45. {
  46. static bool IsVertexCountWithinSupportedRange(size_t vertexOffset, size_t vertexCount)
  47. {
  48. return vertexOffset + vertexCount <= aznumeric_cast<size_t>(SkinnedMeshVertexStreamPropertyInterface::Get()->GetMaxSupportedVertexCount());
  49. }
  50. static void ProcessSkinInfluences(
  51. const EMotionFX::Mesh* mesh,
  52. const EMotionFX::SubMesh* subMesh,
  53. const uint32_t maxInfluencesPerVertex,
  54. AZStd::vector<uint32_t>& blendIndexBufferData,
  55. AZStd::vector<float>& blendWeightBufferData)
  56. {
  57. EMotionFX::SkinningInfoVertexAttributeLayer* sourceSkinningInfo = static_cast<EMotionFX::SkinningInfoVertexAttributeLayer*>(mesh->FindSharedVertexAttributeLayer(EMotionFX::SkinningInfoVertexAttributeLayer::TYPE_ID));
  58. // EMotionFX source gives 16 bit indices and 32 bit float weights
  59. // Atom consumes 32 bit uint indices and 32 bit float weights (range 0-1)
  60. const uint32_t* sourceOriginalVertex = static_cast<uint32_t*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_ORGVTXNUMBERS));
  61. const uint32_t vertexCount = subMesh->GetNumVertices();
  62. const uint32_t vertexStart = subMesh->GetStartVertex();
  63. if (sourceSkinningInfo)
  64. {
  65. for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
  66. {
  67. const uint32_t originalVertex = sourceOriginalVertex[vertexIndex + vertexStart];
  68. const uint32_t influenceCount = AZStd::GetMin<uint32_t>(
  69. maxInfluencesPerVertex, static_cast<uint32_t>(sourceSkinningInfo->GetNumInfluences(originalVertex)));
  70. uint32_t influenceIndex = 0;
  71. for (; influenceIndex < influenceCount; ++influenceIndex)
  72. {
  73. EMotionFX::SkinInfluence* influence = sourceSkinningInfo->GetInfluence(originalVertex, influenceIndex);
  74. // Pack the 16-bit indices into 32-bit uints, putting the first of each index pair in the most significant bits
  75. if (influenceIndex % 2 == 0)
  76. {
  77. blendIndexBufferData.push_back(static_cast<uint32_t>(influence->GetNodeNr()) << 16);
  78. }
  79. else
  80. {
  81. blendIndexBufferData.back() |= static_cast<uint32_t>(influence->GetNodeNr());
  82. }
  83. blendWeightBufferData.push_back(influence->GetWeight());
  84. }
  85. // Zero out any unused ids/weights
  86. for (; influenceIndex < maxInfluencesPerVertex; ++influenceIndex)
  87. {
  88. if (influenceIndex % 2 == 0)
  89. {
  90. blendIndexBufferData.push_back(0);
  91. }
  92. blendWeightBufferData.push_back(0.0f);
  93. }
  94. }
  95. //Pad the blend weight and index buffers in order for it to respect alignment of RPI::SkinnedMeshBufferAlignment
  96. //as that is the expected behavior of the source asset
  97. RPI::ModelAssetHelpers::AlignStreamBuffer<float>(
  98. blendWeightBufferData, blendWeightBufferData.size(), RPI::SkinWeightFormat, RPI::SkinnedMeshBufferAlignment);
  99. //We dont use RPI::SkinIndicesFormat as blendIndexBufferData contains uint32_t instead of uint16_t
  100. RHI::Format blendIndexFormat = RHI::Format::R32_FLOAT;
  101. RPI::ModelAssetHelpers::AlignStreamBuffer<uint32_t>(
  102. blendIndexBufferData, blendIndexBufferData.size(), blendIndexFormat, RPI::SkinnedMeshBufferAlignment);
  103. }
  104. }
  105. static void ProcessMorphsForLod(
  106. uint32_t lodIndex,
  107. const EMotionFX::Actor* actor,
  108. const AZStd::string& fullFileName,
  109. AZStd::intrusive_ptr<SkinnedMeshInputBuffers> skinnedMeshInputBuffers)
  110. {
  111. EMotionFX::MorphSetup* morphSetup = actor->GetMorphSetup(lodIndex);
  112. if (morphSetup)
  113. {
  114. const auto& modelLodAsset = skinnedMeshInputBuffers->GetLod(lodIndex).GetModelLodAsset();
  115. AZ_Assert(actor->GetMorphTargetMetaAsset().IsReady(), "Trying to create morph targets from actor '%s', but the MorphTargetMetaAsset isn't loaded.", actor->GetName());
  116. const AZStd::vector<AZ::RPI::MorphTargetMetaAsset::MorphTarget>& metaDatas = actor->GetMorphTargetMetaAsset()->GetMorphTargets();
  117. // Loop over all the EMotionFX morph targets
  118. const size_t numMorphTargets = morphSetup->GetNumMorphTargets();
  119. for (size_t morphTargetIndex = 0; morphTargetIndex < numMorphTargets; ++morphTargetIndex)
  120. {
  121. EMotionFX::MorphTargetStandard* morphTarget = static_cast<EMotionFX::MorphTargetStandard*>(morphSetup->GetMorphTarget(morphTargetIndex));
  122. for (const auto& metaData : metaDatas)
  123. {
  124. // Loop through the metadatas to find any that correspond with the current morph target.
  125. // There may be more than one, since a single morph target may be distributed across multiple meshes.
  126. // This ensures the order stays in sync with the order in the MorphSetup,
  127. // so that the correct weights are applied to the correct morphs later
  128. // Skip any that don't modify any vertices
  129. if (metaData.m_morphTargetName == morphTarget->GetNameString() && metaData.m_numVertices > 0)
  130. {
  131. // The skinned mesh lod gets a unique morph for each meta, since each one has unique min/max delta values to use for decompression
  132. const AZStd::string morphString = AZStd::string::format(
  133. "%s_Lod%" PRIu32 "_Morph_%s", fullFileName.c_str(), lodIndex, metaData.m_meshNodeName.c_str());
  134. float minWeight = morphTarget->GetRangeMin();
  135. float maxWeight = morphTarget->GetRangeMax();
  136. const auto lodMeshes = modelLodAsset->GetMeshes();
  137. const auto& modelLodMesh = lodMeshes[metaData.m_meshIndex];
  138. const RPI::BufferAssetView* morphBufferAssetView =
  139. modelLodMesh.GetSemanticBufferAssetView(Name{ "MORPHTARGET_VERTEXDELTAS" });
  140. skinnedMeshInputBuffers->AddMorphTarget(
  141. lodIndex, metaData, morphBufferAssetView, morphString, minWeight, maxWeight);
  142. }
  143. }
  144. }
  145. }
  146. }
  147. AZStd::intrusive_ptr<SkinnedMeshInputBuffers> CreateSkinnedMeshInputFromActor(const Data::AssetId& actorAssetId, const EMotionFX::Actor* actor)
  148. {
  149. Data::Asset<RPI::ModelAsset> modelAsset = actor->GetMeshAsset();
  150. if (!modelAsset.IsReady())
  151. {
  152. AZ_Warning("CreateSkinnedMeshInputFromActor", false, "Check if the actor has a mesh added. Right click the source file in the asset browser, click edit settings, "
  153. "and navigate to the Meshes tab. Add a mesh if it's missing.");
  154. return nullptr;
  155. }
  156. AZStd::intrusive_ptr<SkinnedMeshInputBuffers> skinnedMeshInputBuffers = aznew SkinnedMeshInputBuffers;
  157. skinnedMeshInputBuffers->CreateFromModelAsset(modelAsset);
  158. // Get the fileName, which will be used to label the buffers
  159. AZStd::string assetPath;
  160. Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &Data::AssetCatalogRequests::GetAssetPathById, actorAssetId);
  161. AZStd::string fullFileName;
  162. AzFramework::StringFunc::Path::GetFullFileName(assetPath.c_str(), fullFileName);
  163. // GetNumNodes returns the number of 'joints' or 'bones' in the skeleton
  164. const size_t numJoints = actor->GetNumNodes();
  165. const size_t numLODs = actor->GetNumLODLevels();
  166. // Create the containers to hold the data for all the combined sub-meshes
  167. AZStd::vector<uint32_t> blendIndexBufferData;
  168. AZStd::vector<float> blendWeightBufferData;
  169. //
  170. // Process all LODs from the EMotionFX actor data.
  171. //
  172. AZ_Assert(numLODs == modelAsset->GetLodCount(), "The lod count of the EMotionFX mesh and Atom model are out of sync for '%s'", fullFileName.c_str());
  173. for (uint32_t lodIndex = 0; lodIndex < numLODs; ++lodIndex)
  174. {
  175. // Create a single LOD
  176. Data::Asset<RPI::ModelLodAsset> modelLodAsset = modelAsset->GetLodAssets()[lodIndex];
  177. // Clear out the vector for re-mapped joint data that will be populated by values from EMotionFX
  178. blendIndexBufferData.clear();
  179. blendWeightBufferData.clear();
  180. const RPI::BufferAssetView* indicesBuffAssetView =
  181. modelLodAsset->GetSemanticBufferAssetView(Name(RPI::ShaderSemanticName_SkinJointIndices));
  182. const RPI::BufferAssetView* weightsBuffAssetView =
  183. modelLodAsset->GetSemanticBufferAssetView(Name(RPI::ShaderSemanticName_SkinWeights));
  184. // Reserve enough memory for the default/common case. Use the element count from the main source buffer
  185. blendIndexBufferData.reserve(indicesBuffAssetView->GetBufferAsset()->GetBufferViewDescriptor().m_elementCount);
  186. blendWeightBufferData.reserve(weightsBuffAssetView->GetBufferAsset()->GetBufferViewDescriptor().m_elementCount);
  187. // Now iterate over the actual data and populate the data for the per-actor buffers
  188. uint32_t vertexBufferOffset = 0;
  189. for (uint32_t jointIndex = 0; jointIndex < numJoints; ++jointIndex)
  190. {
  191. const EMotionFX::Mesh* mesh = actor->GetMesh(lodIndex, jointIndex);
  192. if (!mesh || mesh->GetIsCollisionMesh())
  193. {
  194. continue;
  195. }
  196. // For each sub-mesh within each mesh, we want to create a separate sub-piece.
  197. const uint32_t numSubMeshes = aznumeric_caster(mesh->GetNumSubMeshes());
  198. AZ_Assert(
  199. numSubMeshes == modelLodAsset->GetMeshes().size(),
  200. "Number of submeshes (%" PRIu32 ") in EMotionFX mesh (lod %d and joint index %d) "
  201. "doesn't match the number of meshes (%d) in model lod asset",
  202. numSubMeshes, lodIndex, jointIndex, modelLodAsset->GetMeshes().size());
  203. for (uint32_t subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex)
  204. {
  205. const EMotionFX::SubMesh* subMesh = mesh->GetSubMesh(static_cast<uint32>(subMeshIndex));
  206. const uint32_t vertexCount = subMesh->GetNumVertices();
  207. // Skip empty sub-meshes and sub-meshes that would put the total vertex count beyond the supported range
  208. if (vertexCount > 0 && IsVertexCountWithinSupportedRange(vertexBufferOffset, vertexCount))
  209. {
  210. ProcessSkinInfluences(mesh, subMesh, skinnedMeshInputBuffers->GetInfluenceCountPerVertex(lodIndex, subMeshIndex), blendIndexBufferData, blendWeightBufferData);
  211. // Increment offsets so that the next sub-mesh can start at the right place
  212. vertexBufferOffset += vertexCount;
  213. }
  214. } // for all submeshes
  215. } // for all meshes
  216. const RPI::BufferAssetView* jointIndicesBufferView = nullptr;
  217. const RPI::BufferAssetView* skinWeightsBufferView = nullptr;
  218. for (const auto& modelLodMesh : modelLodAsset->GetMeshes())
  219. {
  220. // TODO: operate on a per-mesh basis
  221. // If the joint id/weight buffers haven't been found on a mesh yet, keep looking
  222. if (!jointIndicesBufferView)
  223. {
  224. jointIndicesBufferView = modelLodMesh.GetSemanticBufferAssetView(Name{ "SKIN_JOINTINDICES" });
  225. if (jointIndicesBufferView)
  226. {
  227. skinWeightsBufferView = modelLodMesh.GetSemanticBufferAssetView(Name{ "SKIN_WEIGHTS" });
  228. AZ_Error("CreateSkinnedMeshInputFromActor", skinWeightsBufferView, "Mesh '%s' on actor '%s' has joint indices but no joint weights", modelLodMesh.GetName().GetCStr(), fullFileName.c_str());
  229. break;
  230. }
  231. }
  232. }
  233. if (!jointIndicesBufferView || !skinWeightsBufferView)
  234. {
  235. AZ_Error(
  236. "ProcessSkinInfluences", false,
  237. "Actor '%s' lod '%" PRIu32 "' has no skin influences, and will be stuck in bind pose.", fullFileName.c_str(),
  238. lodIndex);
  239. }
  240. else
  241. {
  242. Data::Asset<RPI::BufferAsset> jointIndicesBufferAsset = jointIndicesBufferView->GetBufferAsset();
  243. Data::Asset<RPI::BufferAsset> skinWeightsBufferAsset = skinWeightsBufferView->GetBufferAsset();
  244. // We're using the indices/weights buffers directly from the model.
  245. // However, EMFX has done some re-mapping of the id's, so we need to update the GPU buffer for it to have the correct data.
  246. size_t remappedJointIndexBufferSizeInBytes = blendIndexBufferData.size() * sizeof(blendIndexBufferData[0]);
  247. size_t remappedSkinWeightsBufferSizeInBytes = blendWeightBufferData.size() * sizeof(blendWeightBufferData[0]);
  248. AZ_Assert(jointIndicesBufferAsset->GetBufferDescriptor().m_byteCount == remappedJointIndexBufferSizeInBytes, "Joint indices data from EMotionFX is not the same size as the buffer from the model in '%s', lod '%d'", fullFileName.c_str(), lodIndex);
  249. AZ_Assert(skinWeightsBufferAsset->GetBufferDescriptor().m_byteCount == remappedSkinWeightsBufferSizeInBytes, "Skin weights data from EMotionFX is not the same size as the buffer from the model in '%s', lod '%d'", fullFileName.c_str(), lodIndex);
  250. if (Data::Instance<RPI::Buffer> jointIndicesBuffer = RPI::Buffer::FindOrCreate(jointIndicesBufferAsset))
  251. {
  252. jointIndicesBuffer->UpdateData(blendIndexBufferData.data(), remappedJointIndexBufferSizeInBytes);
  253. }
  254. if (Data::Instance<RPI::Buffer> skinWeightsBuffer = RPI::Buffer::FindOrCreate(skinWeightsBufferAsset))
  255. {
  256. skinWeightsBuffer->UpdateData(blendWeightBufferData.data(), remappedSkinWeightsBufferSizeInBytes);
  257. }
  258. }
  259. ProcessMorphsForLod(lodIndex, actor, fullFileName, skinnedMeshInputBuffers);
  260. } // for all lods
  261. skinnedMeshInputBuffers->Finalize();
  262. return skinnedMeshInputBuffers;
  263. }
  264. void GetBoneTransformsFromActorInstance(const EMotionFX::ActorInstance* actorInstance, AZStd::vector<float>& boneTransforms, EMotionFX::Integration::SkinningMethod skinningMethod)
  265. {
  266. const EMotionFX::TransformData* transforms = actorInstance->GetTransformData();
  267. const AZ::Matrix3x4* skinningMatrices = transforms->GetSkinningMatrices();
  268. // For linear skinning, we need a 3x4 row-major float matrix for each transform
  269. const size_t numBoneTransforms = transforms->GetNumTransforms();
  270. if (skinningMethod == EMotionFX::Integration::SkinningMethod::Linear)
  271. {
  272. boneTransforms.resize_no_construct(numBoneTransforms * LinearSkinningFloatsPerBone);
  273. for (size_t i = 0; i < numBoneTransforms; ++i)
  274. {
  275. skinningMatrices[i].StoreToRowMajorFloat12(&boneTransforms[i * LinearSkinningFloatsPerBone]);
  276. }
  277. }
  278. else if(skinningMethod == EMotionFX::Integration::SkinningMethod::DualQuat)
  279. {
  280. boneTransforms.resize_no_construct(numBoneTransforms * DualQuaternionSkinningFloatsPerBone);
  281. for (size_t i = 0; i < numBoneTransforms; ++i)
  282. {
  283. MCore::DualQuaternion dualQuat = MCore::DualQuaternion::ConvertFromTransform(AZ::Transform::CreateFromMatrix3x4(skinningMatrices[i]));
  284. dualQuat.m_real.StoreToFloat4(&boneTransforms[i * DualQuaternionSkinningFloatsPerBone]);
  285. dualQuat.m_dual.StoreToFloat4(&boneTransforms[i * DualQuaternionSkinningFloatsPerBone + 4]);
  286. }
  287. }
  288. }
  289. Data::Instance<RPI::Buffer> CreateBoneTransformBufferFromActorInstance(const EMotionFX::ActorInstance* actorInstance, EMotionFX::Integration::SkinningMethod skinningMethod)
  290. {
  291. // Get the actual transforms
  292. AZStd::vector<float> boneTransforms;
  293. GetBoneTransformsFromActorInstance(actorInstance, boneTransforms, skinningMethod);
  294. uint32_t floatsPerBone = 0;
  295. if (skinningMethod == EMotionFX::Integration::SkinningMethod::Linear)
  296. {
  297. floatsPerBone = LinearSkinningFloatsPerBone;
  298. }
  299. else if (skinningMethod == EMotionFX::Integration::SkinningMethod::DualQuat)
  300. {
  301. floatsPerBone = DualQuaternionSkinningFloatsPerBone;
  302. }
  303. else
  304. {
  305. AZ_Error("ActorAsset", false, "Unsupported EMotionFX skinning method.");
  306. }
  307. // Create a buffer and populate it with the transforms
  308. RPI::CommonBufferDescriptor descriptor;
  309. descriptor.m_bufferData = boneTransforms.data();
  310. descriptor.m_bufferName = AZStd::string::format("BoneTransformBuffer_%s", actorInstance->GetActor()->GetName());
  311. descriptor.m_byteCount = boneTransforms.size() * sizeof(float);
  312. descriptor.m_elementSize = static_cast<uint32_t>(floatsPerBone * sizeof(float));
  313. descriptor.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
  314. return RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(descriptor);
  315. }
  316. } //namespace Render
  317. } // namespace AZ