ActorAsset.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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. if(!indicesBuffAssetView || !weightsBuffAssetView)
  185. {
  186. AZ_Warning(
  187. "ProcessSkinInfluences", false,
  188. "Actor '%s' lod '%" PRIu32 "' has no skin indice buffer, skinning would not be applicable on this mesh.", fullFileName.c_str(),
  189. lodIndex);
  190. }
  191. else
  192. {
  193. // Reserve enough memory for the default/common case. Use the element count from the main source buffer
  194. blendIndexBufferData.reserve(indicesBuffAssetView->GetBufferAsset()->GetBufferViewDescriptor().m_elementCount);
  195. blendWeightBufferData.reserve(weightsBuffAssetView->GetBufferAsset()->GetBufferViewDescriptor().m_elementCount);
  196. // Now iterate over the actual data and populate the data for the per-actor buffers
  197. uint32_t vertexBufferOffset = 0;
  198. for (uint32_t jointIndex = 0; jointIndex < numJoints; ++jointIndex)
  199. {
  200. const EMotionFX::Mesh* mesh = actor->GetMesh(lodIndex, jointIndex);
  201. if (!mesh || mesh->GetIsCollisionMesh())
  202. {
  203. continue;
  204. }
  205. // For each sub-mesh within each mesh, we want to create a separate sub-piece.
  206. const uint32_t numSubMeshes = aznumeric_caster(mesh->GetNumSubMeshes());
  207. AZ_Assert(
  208. numSubMeshes == modelLodAsset->GetMeshes().size(),
  209. "Number of submeshes (%" PRIu32 ") in EMotionFX mesh (lod %d and joint index %d) "
  210. "doesn't match the number of meshes (%d) in model lod asset",
  211. numSubMeshes, lodIndex, jointIndex, modelLodAsset->GetMeshes().size());
  212. for (uint32_t subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex)
  213. {
  214. const EMotionFX::SubMesh* subMesh = mesh->GetSubMesh(static_cast<uint32>(subMeshIndex));
  215. const uint32_t vertexCount = subMesh->GetNumVertices();
  216. // Skip empty sub-meshes and sub-meshes that would put the total vertex count beyond the supported range
  217. if (vertexCount > 0 && IsVertexCountWithinSupportedRange(vertexBufferOffset, vertexCount))
  218. {
  219. ProcessSkinInfluences(mesh, subMesh, skinnedMeshInputBuffers->GetInfluenceCountPerVertex(lodIndex, subMeshIndex), blendIndexBufferData, blendWeightBufferData);
  220. // Increment offsets so that the next sub-mesh can start at the right place
  221. vertexBufferOffset += vertexCount;
  222. }
  223. } // for all submeshes
  224. } // for all meshes
  225. const RPI::BufferAssetView* jointIndicesBufferView = nullptr;
  226. const RPI::BufferAssetView* skinWeightsBufferView = nullptr;
  227. for (const auto& modelLodMesh : modelLodAsset->GetMeshes())
  228. {
  229. // TODO: operate on a per-mesh basis
  230. // If the joint id/weight buffers haven't been found on a mesh yet, keep looking
  231. if (!jointIndicesBufferView)
  232. {
  233. jointIndicesBufferView = modelLodMesh.GetSemanticBufferAssetView(Name{ "SKIN_JOINTINDICES" });
  234. if (jointIndicesBufferView)
  235. {
  236. skinWeightsBufferView = modelLodMesh.GetSemanticBufferAssetView(Name{ "SKIN_WEIGHTS" });
  237. AZ_Error("CreateSkinnedMeshInputFromActor", skinWeightsBufferView, "Mesh '%s' on actor '%s' has joint indices but no joint weights", modelLodMesh.GetName().GetCStr(), fullFileName.c_str());
  238. break;
  239. }
  240. }
  241. }
  242. if (!jointIndicesBufferView || !skinWeightsBufferView)
  243. {
  244. AZ_Error(
  245. "ProcessSkinInfluences", false,
  246. "Actor '%s' lod '%" PRIu32 "' has no skin influences, and will be stuck in bind pose.", fullFileName.c_str(),
  247. lodIndex);
  248. }
  249. else
  250. {
  251. Data::Asset<RPI::BufferAsset> jointIndicesBufferAsset = jointIndicesBufferView->GetBufferAsset();
  252. Data::Asset<RPI::BufferAsset> skinWeightsBufferAsset = skinWeightsBufferView->GetBufferAsset();
  253. // We're using the indices/weights buffers directly from the model.
  254. // 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.
  255. size_t remappedJointIndexBufferSizeInBytes = blendIndexBufferData.size() * sizeof(blendIndexBufferData[0]);
  256. size_t remappedSkinWeightsBufferSizeInBytes = blendWeightBufferData.size() * sizeof(blendWeightBufferData[0]);
  257. 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);
  258. 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);
  259. if (Data::Instance<RPI::Buffer> jointIndicesBuffer = RPI::Buffer::FindOrCreate(jointIndicesBufferAsset))
  260. {
  261. jointIndicesBuffer->UpdateData(blendIndexBufferData.data(), remappedJointIndexBufferSizeInBytes);
  262. }
  263. if (Data::Instance<RPI::Buffer> skinWeightsBuffer = RPI::Buffer::FindOrCreate(skinWeightsBufferAsset))
  264. {
  265. skinWeightsBuffer->UpdateData(blendWeightBufferData.data(), remappedSkinWeightsBufferSizeInBytes);
  266. }
  267. }
  268. }
  269. ProcessMorphsForLod(lodIndex, actor, fullFileName, skinnedMeshInputBuffers);
  270. } // for all lods
  271. skinnedMeshInputBuffers->Finalize();
  272. return skinnedMeshInputBuffers;
  273. }
  274. void GetBoneTransformsFromActorInstance(const EMotionFX::ActorInstance* actorInstance, AZStd::vector<float>& boneTransforms, EMotionFX::Integration::SkinningMethod skinningMethod)
  275. {
  276. const EMotionFX::TransformData* transforms = actorInstance->GetTransformData();
  277. const AZ::Matrix3x4* skinningMatrices = transforms->GetSkinningMatrices();
  278. // For linear skinning, we need a 3x4 row-major float matrix for each transform
  279. const size_t numBoneTransforms = transforms->GetNumTransforms();
  280. if (skinningMethod == EMotionFX::Integration::SkinningMethod::Linear)
  281. {
  282. boneTransforms.resize_no_construct(numBoneTransforms * LinearSkinningFloatsPerBone);
  283. for (size_t i = 0; i < numBoneTransforms; ++i)
  284. {
  285. skinningMatrices[i].StoreToRowMajorFloat12(&boneTransforms[i * LinearSkinningFloatsPerBone]);
  286. }
  287. }
  288. else if(skinningMethod == EMotionFX::Integration::SkinningMethod::DualQuat)
  289. {
  290. boneTransforms.resize_no_construct(numBoneTransforms * DualQuaternionSkinningFloatsPerBone);
  291. for (size_t i = 0; i < numBoneTransforms; ++i)
  292. {
  293. MCore::DualQuaternion dualQuat = MCore::DualQuaternion::ConvertFromTransform(AZ::Transform::CreateFromMatrix3x4(skinningMatrices[i]));
  294. dualQuat.m_real.StoreToFloat4(&boneTransforms[i * DualQuaternionSkinningFloatsPerBone]);
  295. dualQuat.m_dual.StoreToFloat4(&boneTransforms[i * DualQuaternionSkinningFloatsPerBone + 4]);
  296. }
  297. }
  298. }
  299. Data::Instance<RPI::Buffer> CreateBoneTransformBufferFromActorInstance(const EMotionFX::ActorInstance* actorInstance, EMotionFX::Integration::SkinningMethod skinningMethod)
  300. {
  301. // Get the actual transforms
  302. AZStd::vector<float> boneTransforms;
  303. GetBoneTransformsFromActorInstance(actorInstance, boneTransforms, skinningMethod);
  304. uint32_t floatsPerBone = 0;
  305. if (skinningMethod == EMotionFX::Integration::SkinningMethod::Linear)
  306. {
  307. floatsPerBone = LinearSkinningFloatsPerBone;
  308. }
  309. else if (skinningMethod == EMotionFX::Integration::SkinningMethod::DualQuat)
  310. {
  311. floatsPerBone = DualQuaternionSkinningFloatsPerBone;
  312. }
  313. else if (skinningMethod == EMotionFX::Integration::SkinningMethod::None)
  314. {
  315. AZ_Warning("ActorAsset", false, "Create bone transform called with no skinning, will return nullptr.");
  316. return nullptr;
  317. }
  318. else
  319. {
  320. AZ_Error("ActorAsset", false, "Unsupported EMotionFX skinning method.");
  321. }
  322. // Create a buffer and populate it with the transforms
  323. RPI::CommonBufferDescriptor descriptor;
  324. descriptor.m_bufferData = boneTransforms.data();
  325. descriptor.m_bufferName = AZStd::string::format("BoneTransformBuffer_%s", actorInstance->GetActor()->GetName());
  326. descriptor.m_byteCount = boneTransforms.size() * sizeof(float);
  327. descriptor.m_elementSize = static_cast<uint32_t>(floatsPerBone * sizeof(float));
  328. descriptor.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
  329. return RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(descriptor);
  330. }
  331. } //namespace Render
  332. } // namespace AZ