EMFX - Refactor the emfx actor asset loading. (#1101)
Refactor emfx asset loading. The mesh asset, skinMetaAsset and morphTargetMeta asset are part of the dependency.
This commit is contained in:
@@ -94,8 +94,9 @@ namespace CommandSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
actor->LoadRemainingAssets();
|
||||
actor->CheckFinalizeActor();
|
||||
// Because the actor is directly loaded from disk (without going through an actor asset), we need to ask for a blocking
|
||||
// load for the asset that actor is depend on.
|
||||
actor->Finalize(EMotionFX::Actor::LoadRequirement::RequireBlockingLoad);
|
||||
|
||||
// set the actor id in case we have specified it as parameter
|
||||
if (actorID != MCORE_INVALIDINDEX32)
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace EMotionFX
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<ActorGroupExporter, AZ::SceneAPI::SceneCore::ExportingComponent>()->Version(1);
|
||||
serializeContext->Class<ActorGroupExporter, AZ::SceneAPI::SceneCore::ExportingComponent>()->Version(2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,21 +117,6 @@ namespace EMotionFX
|
||||
|
||||
ExporterLib::SaveActor(filename, m_actor.get(), MCore::Endian::ENDIAN_LITTLE, GetMeshAssetId(context));
|
||||
|
||||
#ifdef EMOTIONFX_ACTOR_DEBUG
|
||||
// Use there line to create a log file and inspect detail debug info
|
||||
AZStd::string folderPath;
|
||||
AzFramework::StringFunc::Path::GetFolderPath(filename.c_str(), folderPath);
|
||||
AZStd::string logFilename = folderPath;
|
||||
logFilename += "EMotionFXExporter_Log.txt";
|
||||
MCore::GetLogManager().CreateLogFile(logFilename.c_str());
|
||||
EMotionFX::GetImporter().SetLogDetails(true);
|
||||
filename += ".xac";
|
||||
|
||||
// use this line to load the actor from the saved actor file
|
||||
EMotionFX::Actor* testLoadingActor = EMotionFX::GetImporter().LoadActor(AZStd::string(filename.c_str()));
|
||||
MCore::Destroy(testLoadingActor);
|
||||
#endif // EMOTIONFX_ACTOR_DEBUG
|
||||
|
||||
static AZ::Data::AssetType emotionFXActorAssetType("{F67CC648-EA51-464C-9F5D-4A9CE41A7F86}"); // from ActorAsset.h in EMotionFX Gem
|
||||
AZ::SceneAPI::Events::ExportProduct& product = context.m_products.AddProduct(AZStd::move(filename), context.m_group.GetId(), emotionFXActorAssetType,
|
||||
AZStd::nullopt, AZStd::nullopt);
|
||||
@@ -141,6 +126,26 @@ namespace EMotionFX
|
||||
product.m_legacyPathDependencies.emplace_back(AZStd::move(materialPathReference));
|
||||
}
|
||||
|
||||
// Mesh asset, skin meta asset and morph target meta asset are sub assets for actor asset.
|
||||
// In here we set them as the dependency of the actor asset. That make sure those assets get automatically loaded before actor asset.
|
||||
// Default to the first product until we are able to establish a link between mesh and actor (ATOM-13590).
|
||||
const AZ::Data::AssetType assetDependencyList[] = {
|
||||
azrtti_typeid<AZ::RPI::ModelAsset>(),
|
||||
azrtti_typeid<AZ::RPI::SkinMetaAsset>(),
|
||||
azrtti_typeid<AZ::RPI::MorphTargetMetaAsset>()
|
||||
};
|
||||
|
||||
for (const AZ::Data::AssetType& assetDependency : assetDependencyList)
|
||||
{
|
||||
AZStd::optional<AZ::SceneAPI::Events::ExportProduct> result = GetFirstProductByType(context, assetDependency);
|
||||
if (result != AZStd::nullopt)
|
||||
{
|
||||
AZ::SceneAPI::Events::ExportProduct exportProduct = result.value();
|
||||
exportProduct.m_dependencyFlags = AZ::Data::ProductDependencyInfo::CreateFlags(AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
product.m_productDependencies.emplace_back(exportProduct);
|
||||
}
|
||||
}
|
||||
|
||||
return SceneEvents::ProcessingResult::Success;
|
||||
}
|
||||
|
||||
@@ -171,5 +176,20 @@ namespace EMotionFX
|
||||
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::SceneAPI::Events::ExportProduct> ActorGroupExporter::GetFirstProductByType(
|
||||
const ActorGroupExportContext& context, AZ::Data::AssetType type)
|
||||
{
|
||||
const AZStd::vector<AZ::SceneAPI::Events::ExportProduct>& products = context.m_products.GetProducts();
|
||||
for (const AZ::SceneAPI::Events::ExportProduct& product : products)
|
||||
{
|
||||
if (product.m_assetType == type)
|
||||
{
|
||||
return product;
|
||||
}
|
||||
}
|
||||
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
} // namespace Pipeline
|
||||
} // namespace EMotionFX
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <EMotionFX/Source/AutoRegisteredActor.h>
|
||||
#include <SceneAPI/SceneCore/Components/ExportingComponent.h>
|
||||
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
|
||||
#include <Integration/System/SystemCommon.h>
|
||||
|
||||
|
||||
@@ -44,6 +45,8 @@ namespace EMotionFX
|
||||
|
||||
//! Get the mesh asset id to which the actor is linked to by default.
|
||||
AZStd::optional<AZ::Data::AssetId> GetMeshAssetId(const ActorGroupExportContext& context) const;
|
||||
static AZStd::optional<AZ::SceneAPI::Events::ExportProduct> GetFirstProductByType(
|
||||
const ActorGroupExportContext& context, AZ::Data::AssetType type);
|
||||
|
||||
AutoRegisteredActor m_actor;
|
||||
AZStd::vector<AZStd::string> m_actorMaterialReferences;
|
||||
|
||||
@@ -125,7 +125,6 @@ namespace EMotionFX
|
||||
|
||||
Actor::~Actor()
|
||||
{
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect();
|
||||
ActorNotificationBus::Broadcast(&ActorNotificationBus::Events::OnActorDestroyed, this);
|
||||
GetEventManager().OnDeleteActor(this);
|
||||
|
||||
@@ -1463,108 +1462,78 @@ namespace EMotionFX
|
||||
return morphTargetMetaAssetInfo.m_assetId.IsValid();
|
||||
}
|
||||
|
||||
void Actor::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (asset == m_meshAsset)
|
||||
{
|
||||
m_meshAsset = asset;
|
||||
}
|
||||
if (asset == m_skinMetaAsset)
|
||||
{
|
||||
m_skinMetaAsset = asset;
|
||||
}
|
||||
if (asset == m_morphTargetMetaAsset)
|
||||
{
|
||||
m_morphTargetMetaAsset = asset;
|
||||
}
|
||||
|
||||
CheckFinalizeActor();
|
||||
}
|
||||
|
||||
void Actor::CheckFinalizeActor()
|
||||
void Actor::Finalize(LoadRequirement loadReq)
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::recursive_mutex> lock(m_mutex);
|
||||
|
||||
if (m_meshAsset.IsReady())
|
||||
// Load the mesh asset, skin meta asset and morph target asset.
|
||||
// Those sub assets should have already been setup as dependency of actor asset, so they should already be loaded when we reach here.
|
||||
// Only exception is that when the actor is not loaded by an actor asset, for which we need to do a blocking load.
|
||||
if (m_meshAssetId.IsValid())
|
||||
{
|
||||
const AZ::Data::AssetId meshAssetId = m_meshAsset.GetId();
|
||||
const bool skinMetaAssetExists = DoesSkinMetaAssetExist(meshAssetId);
|
||||
const bool morphTargetMetaAssetExists = DoesMorphTargetMetaAssetExist(m_meshAsset.GetId());
|
||||
// Get the mesh asset.
|
||||
m_meshAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::ModelAsset>(m_meshAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
|
||||
m_skinToSkeletonIndexMap.clear();
|
||||
|
||||
// Skin and morph target meta assets are ready, fill the runtime mesh data.
|
||||
if ((!skinMetaAssetExists || m_skinMetaAsset.IsReady()) &&
|
||||
(!morphTargetMetaAssetExists || m_morphTargetMetaAsset.IsReady()))
|
||||
// Get the skin meta asset.
|
||||
const AZ::Data::AssetId skinMetaAssetId = ConstructSkinMetaAssetId(m_meshAssetId);
|
||||
if (DoesSkinMetaAssetExist(m_meshAssetId) && skinMetaAssetId.IsValid())
|
||||
{
|
||||
// Optional, not all actors have a skinned meshes.
|
||||
if (skinMetaAssetExists)
|
||||
m_skinMetaAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::SkinMetaAsset>(
|
||||
skinMetaAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
}
|
||||
|
||||
// Get the morph target meta asset.
|
||||
const AZ::Data::AssetId morphTargetMetaAssetId = ConstructMorphTargetMetaAssetId(m_meshAssetId);
|
||||
if (DoesMorphTargetMetaAssetExist(m_meshAssetId) && morphTargetMetaAssetId.IsValid())
|
||||
{
|
||||
m_morphTargetMetaAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::MorphTargetMetaAsset>(
|
||||
morphTargetMetaAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
}
|
||||
|
||||
if (loadReq == LoadRequirement::RequireBlockingLoad)
|
||||
{
|
||||
if (m_skinMetaAsset.IsLoading())
|
||||
{
|
||||
m_skinToSkeletonIndexMap = ConstructSkinToSkeletonIndexMap(m_skinMetaAsset);
|
||||
m_skinMetaAsset.BlockUntilLoadComplete();
|
||||
}
|
||||
|
||||
ConstructMeshes(m_skinToSkeletonIndexMap);
|
||||
|
||||
// Optional, not all actors have morph targets.
|
||||
if (morphTargetMetaAssetExists)
|
||||
if (m_morphTargetMetaAsset.IsLoading())
|
||||
{
|
||||
ConstructMorphTargets();
|
||||
m_morphTargetMetaAsset.BlockUntilLoadComplete();
|
||||
}
|
||||
else
|
||||
if (m_meshAsset.IsLoading())
|
||||
{
|
||||
// Optional, not all actors have morph targets.
|
||||
const size_t numLODLevels = m_meshAsset->GetLodAssets().size();
|
||||
mMorphSetups.Resize(numLODLevels);
|
||||
for (AZ::u32 i = 0; i < numLODLevels; ++i)
|
||||
{
|
||||
mMorphSetups[i] = nullptr;
|
||||
}
|
||||
m_meshAsset.BlockUntilLoadComplete();
|
||||
}
|
||||
|
||||
SetActorReady();
|
||||
|
||||
// Do not release the mesh assets. We need the mesh data to initialize future instances of the render actor instances.
|
||||
//m_meshAsset.Release();
|
||||
//m_skinMetaAsset.Release();
|
||||
//m_morphTargetMetaAsset.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::LoadRemainingAssets()
|
||||
{
|
||||
// Everything is ready already or no (skeleton-only) or an invalid mesh asset assigned. Emit ready signal directly.
|
||||
if (m_isReady || !m_meshAssetId.IsValid())
|
||||
if (m_meshAsset.IsReady())
|
||||
{
|
||||
SetActorReady();
|
||||
return;
|
||||
if (m_skinMetaAsset.IsReady())
|
||||
{
|
||||
m_skinToSkeletonIndexMap = ConstructSkinToSkeletonIndexMap(m_skinMetaAsset);
|
||||
}
|
||||
ConstructMeshes();
|
||||
|
||||
if (m_morphTargetMetaAsset.IsReady())
|
||||
{
|
||||
ConstructMorphTargets();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Optional, not all actors have morph targets.
|
||||
const size_t numLODLevels = m_meshAsset->GetLodAssets().size();
|
||||
mMorphSetups.Resize(numLODLevels);
|
||||
for (AZ::u32 i = 0; i < numLODLevels; ++i)
|
||||
{
|
||||
mMorphSetups[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoadMeshAssetsQueued();
|
||||
}
|
||||
|
||||
void Actor::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (asset == m_meshAsset)
|
||||
{
|
||||
m_meshAsset = asset;
|
||||
}
|
||||
if (asset == m_skinMetaAsset)
|
||||
{
|
||||
m_skinMetaAsset = asset;
|
||||
}
|
||||
if (asset == m_morphTargetMetaAsset)
|
||||
{
|
||||
m_morphTargetMetaAsset = asset;
|
||||
}
|
||||
|
||||
CheckFinalizeActor();
|
||||
}
|
||||
|
||||
void Actor::SetActorReady()
|
||||
{
|
||||
m_isReady = true;
|
||||
ActorNotificationBus::Broadcast(&ActorNotificationBus::Events::OnActorReady, this);
|
||||
// Do not release the mesh assets. We need the mesh data to initialize future instances of the render actor instances.
|
||||
}
|
||||
|
||||
// update the static AABB (very heavy as it has to create an actor instance, update mesh deformers, calculate the mesh based bounds etc)
|
||||
@@ -2792,37 +2761,6 @@ namespace EMotionFX
|
||||
m_meshAssetId = assetId;
|
||||
}
|
||||
|
||||
void Actor::LoadMeshAssetsQueued()
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::recursive_mutex> lock(m_mutex);
|
||||
|
||||
// Mesh asset will be queue loaded on post init.
|
||||
if (m_meshAssetId.IsValid())
|
||||
{
|
||||
m_isReady = false;
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect();
|
||||
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(m_meshAssetId);
|
||||
m_meshAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::ModelAsset>(m_meshAssetId, AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
// Skin meta asset
|
||||
if (DoesSkinMetaAssetExist(m_meshAssetId))
|
||||
{
|
||||
const AZ::Data::AssetId skinMetaAssetId = ConstructSkinMetaAssetId(m_meshAssetId);
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(skinMetaAssetId);
|
||||
m_skinMetaAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::SkinMetaAsset>(skinMetaAssetId, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
// Morph target meta asset
|
||||
if (DoesMorphTargetMetaAssetExist(m_meshAssetId))
|
||||
{
|
||||
const AZ::Data::AssetId morphTargetMetaAssetId = ConstructMorphTargetMetaAssetId(m_meshAssetId);
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(morphTargetMetaAssetId);
|
||||
m_morphTargetMetaAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::MorphTargetMetaAsset>(morphTargetMetaAssetId, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node* Actor::FindMeshJoint(const AZ::Data::Asset<AZ::RPI::ModelLodAsset>& lodModelAsset) const
|
||||
{
|
||||
const AZStd::array_view<AZ::RPI::ModelLodAsset::Mesh>& sourceMeshes = lodModelAsset->GetMeshes();
|
||||
@@ -2843,7 +2781,7 @@ namespace EMotionFX
|
||||
return mSkeleton->GetNode(0);
|
||||
}
|
||||
|
||||
void Actor::ConstructMeshes(const AZStd::unordered_map<AZ::u16, AZ::u16>& skinToSkeletonIndexMap)
|
||||
void Actor::ConstructMeshes()
|
||||
{
|
||||
AZ_Assert(m_meshAsset.IsReady(), "Mesh asset should be fully loaded and ready.");
|
||||
|
||||
@@ -2855,7 +2793,8 @@ namespace EMotionFX
|
||||
SetNumLODLevels(numLODLevels, /*adjustMorphSetup=*/false);
|
||||
const uint32 numNodes = mSkeleton->GetNumNodes();
|
||||
|
||||
// Remove all the materials and add them back based on the meshAsset. Eventually we will remove all the material from Actor and GLActor.
|
||||
// Remove all the materials and add them back based on the meshAsset. Eventually we will remove all the material from Actor and
|
||||
// GLActor.
|
||||
RemoveAllMaterials();
|
||||
mMaterials.Resize(numLODLevels);
|
||||
|
||||
@@ -2866,7 +2805,7 @@ namespace EMotionFX
|
||||
lodLevels[lodLevel].mNodeInfos.Resize(numNodes);
|
||||
|
||||
// Create a single mesh for the actor.
|
||||
Mesh* mesh = Mesh::CreateFromModelLod(lodAsset, skinToSkeletonIndexMap);
|
||||
Mesh* mesh = Mesh::CreateFromModelLod(lodAsset, m_skinToSkeletonIndexMap);
|
||||
|
||||
// Find an owning joint for the mesh.
|
||||
Node* meshJoint = FindMeshJoint(lodAsset);
|
||||
@@ -2896,13 +2835,14 @@ namespace EMotionFX
|
||||
continue;
|
||||
}
|
||||
|
||||
EMotionFX::SkinningInfoVertexAttributeLayer* skinLayer = static_cast<EMotionFX::SkinningInfoVertexAttributeLayer*>(vertexAttributeLayer);
|
||||
EMotionFX::SkinningInfoVertexAttributeLayer* skinLayer =
|
||||
static_cast<EMotionFX::SkinningInfoVertexAttributeLayer*>(vertexAttributeLayer);
|
||||
const AZ::u32 numOrgVerts = skinLayer->GetNumAttributes();
|
||||
AZStd::set<AZ::u32> localJointIndices = skinLayer->CalcLocalJointIndices(numOrgVerts);
|
||||
const AZ::u32 numLocalJoints = static_cast<AZ::u32>(localJointIndices.size());
|
||||
|
||||
// The information about if we want to use dual quat skinning is baked into the mesh chunk and we don't have access to that anymore.
|
||||
// Default to dual quat skinning.
|
||||
// The information about if we want to use dual quat skinning is baked into the mesh chunk and we don't have access to that
|
||||
// anymore. Default to dual quat skinning.
|
||||
const bool dualQuatSkinning = true;
|
||||
if (dualQuatSkinning)
|
||||
{
|
||||
@@ -2970,7 +2910,8 @@ namespace EMotionFX
|
||||
|
||||
void Actor::ConstructMorphTargets()
|
||||
{
|
||||
AZ_Assert(m_meshAsset.IsReady() && m_morphTargetMetaAsset.IsReady(), "Mesh as well as morph target meta asset asset should be fully loaded and ready.");
|
||||
AZ_Assert(m_meshAsset.IsReady() && m_morphTargetMetaAsset.IsReady(),
|
||||
"Mesh as well as morph target meta asset asset should be fully loaded and ready.");
|
||||
AZStd::vector<LODLevel>& lodLevels = m_meshLodData.m_lodLevels;
|
||||
const AZStd::array_view<AZ::Data::Asset<AZ::RPI::ModelLodAsset>>& lodAssets = m_meshAsset->GetLodAssets();
|
||||
const size_t numLODLevels = lodAssets.size();
|
||||
|
||||
@@ -63,7 +63,6 @@ namespace EMotionFX
|
||||
* still share the same data from the Actor class. The Actor contains information about the hierarchy/structure of the characters.
|
||||
*/
|
||||
class EMFX_API Actor
|
||||
: private AZ::Data::AssetBus::MultiHandler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR_DECL
|
||||
@@ -101,6 +100,12 @@ namespace EMotionFX
|
||||
uint8 mFlags; // bitfield with MIRRORFLAG_ prefix
|
||||
};
|
||||
|
||||
enum class LoadRequirement : bool
|
||||
{
|
||||
RequireBlockingLoad,
|
||||
AllowAsyncLoad
|
||||
};
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -885,36 +890,35 @@ namespace EMotionFX
|
||||
bool GetOptimizeSkeleton() const { return m_optimizeSkeleton; }
|
||||
|
||||
void SetMeshAssetId(const AZ::Data::AssetId& assetId);
|
||||
void CheckFinalizeActor();
|
||||
void LoadMeshAssetsQueued();
|
||||
void LoadRemainingAssets();
|
||||
AZ::Data::AssetId GetMeshAssetId() const { return m_meshAssetId; };
|
||||
|
||||
const AZ::Data::Asset<AZ::RPI::ModelAsset>& GetMeshAsset() const { return m_meshAsset; }
|
||||
const AZ::Data::Asset<AZ::RPI::SkinMetaAsset>& GetSkinMetaAsset() const { return m_skinMetaAsset; }
|
||||
const AZ::Data::Asset<AZ::RPI::MorphTargetMetaAsset>& GetMorphTargetMetaAsset() const { return m_morphTargetMetaAsset; }
|
||||
|
||||
const AZStd::unordered_map<AZ::u16, AZ::u16>& GetSkinToSkeletonIndexMap() const { return m_skinToSkeletonIndexMap; }
|
||||
|
||||
void SetMeshAsset(AZ::Data::Asset<AZ::RPI::ModelAsset> asset) { m_meshAsset = asset; }
|
||||
void SetSkinMetaAsset(AZ::Data::Asset<AZ::RPI::SkinMetaAsset> asset) { m_skinMetaAsset = asset; }
|
||||
void SetMorphTargetMetaAsset(AZ::Data::Asset<AZ::RPI::MorphTargetMetaAsset> asset) { m_morphTargetMetaAsset = asset; }
|
||||
/**
|
||||
* Is the actor fully ready?
|
||||
* @result True in case the actor as well as its dependent files (e.g. mesh, skin, morph targets) are fully loaded and initialized.
|
||||
**/
|
||||
bool IsReady() const { return m_isReady; }
|
||||
|
||||
/**
|
||||
* Is the actor fully ready?
|
||||
* @result True in case the actor as well as its dependent files (e.g. mesh, skin, morph targets) are fully loaded and initialized.
|
||||
**/
|
||||
bool IsReady() const { return m_isReady; }
|
||||
* Finalize the actor with preload assets (mesh, skinmeta and morph target assets).
|
||||
* LoadRequirement - We won't need a blocking load if the actor is part of the actor asset, as that will trigger the preload assets
|
||||
* to load and get ready before finalize has been reached.
|
||||
* However, if we are calling this on an actor that bypassed the asset system (e.g loading the actor directly from disk), it will require
|
||||
* a blocking load. This option is now being used because emfx editor does not fully integrate with the asset system.
|
||||
*/
|
||||
void Finalize(LoadRequirement loadReq = LoadRequirement::AllowAsyncLoad);
|
||||
|
||||
private:
|
||||
void InsertJointAndParents(AZ::u32 jointIndex, AZStd::unordered_set<AZ::u32>& includedJointIndices);
|
||||
|
||||
// AZ::Data::AssetBus::Handler
|
||||
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
|
||||
AZStd::unordered_map<AZ::u16, AZ::u16> ConstructSkinToSkeletonIndexMap(const AZ::Data::Asset<AZ::RPI::SkinMetaAsset>& skinMetaAsset);
|
||||
void ConstructMeshes(const AZStd::unordered_map<AZ::u16, AZ::u16>& skinToSkeletonIndexMap);
|
||||
void ConstructMeshes();
|
||||
void ConstructMorphTargets();
|
||||
|
||||
Node* FindJointByMeshName(const AZStd::string_view meshName) const;
|
||||
|
||||
// per node info (shared between lods)
|
||||
@@ -966,9 +970,6 @@ namespace EMotionFX
|
||||
|
||||
Node* FindMeshJoint(const AZ::Data::Asset<AZ::RPI::ModelLodAsset>& lodModelAsset) const;
|
||||
|
||||
void SetActorReady();
|
||||
bool m_isReady = false;
|
||||
|
||||
Skeleton* mSkeleton; /**< The skeleton, containing the nodes and bind pose. */
|
||||
MCore::Array<Dependency> mDependencies; /**< The dependencies on other actors (shared meshes and transforms). */
|
||||
AZStd::vector<NodeInfo> mNodeInfos; /**< The per node info, shared between lods. */
|
||||
@@ -992,7 +993,7 @@ namespace EMotionFX
|
||||
bool mDirtyFlag; /**< The dirty flag which indicates whether the user has made changes to the actor since the last file save operation. */
|
||||
bool mUsedForVisualization; /**< Indicates if the actor is used for visualization specific things and is not used as a normal in-game actor. */
|
||||
bool m_optimizeSkeleton; /**< Indicates if we should perform/ */
|
||||
|
||||
bool m_isReady = false; /**< If actor as well as its dependent files are fully loaded and initialized.*/
|
||||
#if defined(EMFX_DEVELOPMENT_BUILD)
|
||||
bool mIsOwnedByRuntime; /**< Set if the actor is used/owned by the engine runtime. */
|
||||
#endif // EMFX_DEVELOPMENT_BUILD
|
||||
|
||||
@@ -68,6 +68,9 @@ namespace EMotionFX
|
||||
&actorSettings,
|
||||
"");
|
||||
|
||||
assetData->m_emfxActor->Finalize();
|
||||
|
||||
// Clear out the EMFX raw asset data.
|
||||
assetData->ReleaseEMotionFXData();
|
||||
|
||||
if (!assetData->m_emfxActor)
|
||||
|
||||
@@ -154,17 +154,15 @@ namespace EMotionFX
|
||||
Actor* actor = m_configuration.m_actorAsset->GetActor();
|
||||
if (actor)
|
||||
{
|
||||
OnActorReady(actor);
|
||||
CheckActorCreation();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ActorComponent::ActorComponent(const Configuration* configuration)
|
||||
: m_debugDrawRoot(false)
|
||||
, m_sceneFinishSimHandler([this](
|
||||
[[maybe_unused]] AzPhysics::SceneHandle sceneHandle,
|
||||
float fixedDeltatime
|
||||
)
|
||||
, m_sceneFinishSimHandler([this]([[maybe_unused]] AzPhysics::SceneHandle sceneHandle,
|
||||
float fixedDeltatime)
|
||||
{
|
||||
if (m_actorInstance)
|
||||
{
|
||||
@@ -192,18 +190,9 @@ namespace EMotionFX
|
||||
|
||||
if (cfg.m_actorAsset.GetId().IsValid())
|
||||
{
|
||||
EMotionFX::ActorNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
EMotionFX::ActorNotificationBus::Handler::BusConnect();
|
||||
AZ::Data::AssetBus::Handler::BusConnect(cfg.m_actorAsset.GetId());
|
||||
cfg.m_actorAsset.QueueLoad();
|
||||
|
||||
// In case the asset was already loaded fully, create the actor directly.
|
||||
if (cfg.m_actorAsset.IsReady() &&
|
||||
cfg.m_actorAsset->GetActor())
|
||||
{
|
||||
cfg.m_actorAsset->GetActor()->LoadRemainingAssets();
|
||||
}
|
||||
}
|
||||
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
@@ -231,7 +220,6 @@ namespace EMotionFX
|
||||
LmbrCentral::AttachmentComponentNotificationBus::Handler::BusDisconnect();
|
||||
AZ::TransformNotificationBus::MultiHandler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
EMotionFX::ActorNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
DestroyActor();
|
||||
m_configuration.m_actorAsset.Release();
|
||||
@@ -314,28 +302,12 @@ namespace EMotionFX
|
||||
Actor* actor = m_configuration.m_actorAsset->GetActor();
|
||||
AZ_Assert(m_configuration.m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid.");
|
||||
|
||||
actor->LoadRemainingAssets();
|
||||
actor->CheckFinalizeActor();
|
||||
CheckActorCreation();
|
||||
}
|
||||
|
||||
void ActorComponent::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
DestroyActor();
|
||||
m_configuration.m_actorAsset = asset;
|
||||
|
||||
const Actor* oldActor = m_configuration.m_actorAsset->GetActor();
|
||||
AZ::Data::Asset<AZ::RPI::ModelAsset> meshAsset = oldActor->GetMeshAsset();
|
||||
AZ::Data::Asset<AZ::RPI::SkinMetaAsset> skinMetaAsset = oldActor->GetSkinMetaAsset();
|
||||
AZ::Data::Asset<AZ::RPI::MorphTargetMetaAsset> morphTargetMetaAsset = oldActor->GetMorphTargetMetaAsset();
|
||||
|
||||
m_configuration.m_actorAsset = asset;
|
||||
Actor* newActor = m_configuration.m_actorAsset->GetActor();
|
||||
AZ_Assert(m_configuration.m_actorAsset.IsReady() && newActor, "Actor asset should be loaded and actor valid.");
|
||||
|
||||
newActor->SetMeshAsset(meshAsset);
|
||||
newActor->SetSkinMetaAsset(skinMetaAsset);
|
||||
newActor->SetMorphTargetMetaAsset(morphTargetMetaAsset);
|
||||
newActor->CheckFinalizeActor();
|
||||
OnAssetReady(asset);
|
||||
}
|
||||
|
||||
bool ActorComponent::IsPhysicsSceneSimulationFinishEventConnected() const
|
||||
@@ -850,13 +822,5 @@ namespace EMotionFX
|
||||
m_actorInstance->RemoveAttachment(targetActorInstance);
|
||||
}
|
||||
}
|
||||
|
||||
void ActorComponent::OnActorReady(Actor* actor)
|
||||
{
|
||||
if (m_configuration.m_actorAsset && m_configuration.m_actorAsset->GetActor() == actor)
|
||||
{
|
||||
CheckActorCreation();
|
||||
}
|
||||
}
|
||||
} // namespace Integration
|
||||
} // namespace EMotionFX
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace EMotionFX
|
||||
, private LmbrCentral::AttachmentComponentNotificationBus::Handler
|
||||
, private AzFramework::CharacterPhysicsDataRequestBus::Handler
|
||||
, private AzFramework::RagdollPhysicsNotificationBus::Handler
|
||||
, private EMotionFX::ActorNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ActorComponent, "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}");
|
||||
@@ -168,9 +167,6 @@ namespace EMotionFX
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
int GetTickOrder() override;
|
||||
|
||||
// ActorNotificationBus::Handler
|
||||
void OnActorReady(Actor* actor) override;
|
||||
|
||||
void CheckActorCreation();
|
||||
void DestroyActor();
|
||||
void CheckAttachToEntity();
|
||||
|
||||
@@ -156,8 +156,6 @@ namespace EMotionFX
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void EditorActorComponent::Activate()
|
||||
{
|
||||
EMotionFX::ActorNotificationBus::Handler::BusConnect();
|
||||
|
||||
LoadActorAsset();
|
||||
|
||||
const AZ::EntityId entityId = GetEntityId();
|
||||
@@ -186,8 +184,6 @@ namespace EMotionFX
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
|
||||
EMotionFX::ActorNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
DestroyActorInstance();
|
||||
m_actorAsset.Release();
|
||||
}
|
||||
@@ -234,13 +230,6 @@ namespace EMotionFX
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusConnect(m_actorAsset.GetId());
|
||||
m_actorAsset.QueueLoad();
|
||||
|
||||
// In case the asset was already loaded fully, create the actor directly.
|
||||
if (m_actorAsset.IsReady() &&
|
||||
m_actorAsset->GetActor())
|
||||
{
|
||||
m_actorAsset->GetActor()->LoadRemainingAssets();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -475,27 +464,13 @@ namespace EMotionFX
|
||||
Actor* actor = m_actorAsset->GetActor();
|
||||
AZ_Assert(m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid.");
|
||||
|
||||
actor->LoadRemainingAssets();
|
||||
actor->CheckFinalizeActor();
|
||||
CheckActorCreation();
|
||||
}
|
||||
|
||||
void EditorActorComponent::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
DestroyActorInstance();
|
||||
|
||||
const Actor* oldActor = m_actorAsset->GetActor();
|
||||
AZ::Data::Asset<AZ::RPI::ModelAsset> meshAsset = oldActor->GetMeshAsset();
|
||||
AZ::Data::Asset<AZ::RPI::SkinMetaAsset> skinMetaAsset = oldActor->GetSkinMetaAsset();
|
||||
AZ::Data::Asset<AZ::RPI::MorphTargetMetaAsset> morphTargetMetaAsset = oldActor->GetMorphTargetMetaAsset();
|
||||
|
||||
m_actorAsset = asset;
|
||||
Actor* newActor = m_actorAsset->GetActor();
|
||||
AZ_Assert(m_actorAsset.IsReady() && newActor, "Actor asset should be loaded and actor valid.");
|
||||
|
||||
newActor->SetMeshAsset(meshAsset);
|
||||
newActor->SetSkinMetaAsset(skinMetaAsset);
|
||||
newActor->SetMorphTargetMetaAsset(morphTargetMetaAsset);
|
||||
newActor->CheckFinalizeActor();
|
||||
OnAssetReady(asset);
|
||||
}
|
||||
|
||||
void EditorActorComponent::SetActorAsset(AZ::Data::Asset<ActorAsset> actorAsset)
|
||||
@@ -505,7 +480,7 @@ namespace EMotionFX
|
||||
Actor* actor = m_actorAsset->GetActor();
|
||||
if (actor)
|
||||
{
|
||||
OnActorReady(actor);
|
||||
CheckActorCreation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,14 +793,6 @@ namespace EMotionFX
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorActorComponent::OnActorReady(Actor* actor)
|
||||
{
|
||||
if (m_actorAsset && m_actorAsset->GetActor() == actor)
|
||||
{
|
||||
CheckActorCreation();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorActorComponent::CheckActorCreation()
|
||||
{
|
||||
// Enable/disable debug drawing.
|
||||
|
||||
@@ -45,7 +45,6 @@ namespace EMotionFX
|
||||
, private AzToolsFramework::EditorComponentSelectionRequestsBus::Handler
|
||||
, private AzToolsFramework::EditorVisibilityNotificationBus::Handler
|
||||
, public AzFramework::BoundsRequestBus::Handler
|
||||
, private EMotionFX::ActorNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_EDITOR_COMPONENT(EditorActorComponent, "{A863EE1B-8CFD-4EDD-BA0D-1CEC2879AD44}");
|
||||
@@ -142,9 +141,6 @@ namespace EMotionFX
|
||||
void OnAttached(AZ::EntityId targetId) override;
|
||||
void OnDetached(AZ::EntityId targetId) override;
|
||||
|
||||
// ActorNotificationBus::Handler
|
||||
void OnActorReady(Actor* actor) override;
|
||||
|
||||
void CheckActorCreation();
|
||||
void BuildGameEntity(AZ::Entity* gameEntity) override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user