|
|
|
|
@ -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);
|
|
|
|
|
|
|
|
|
|
// Get the skin meta asset.
|
|
|
|
|
const AZ::Data::AssetId skinMetaAssetId = ConstructSkinMetaAssetId(m_meshAssetId);
|
|
|
|
|
if (DoesSkinMetaAssetExist(m_meshAssetId) && skinMetaAssetId.IsValid())
|
|
|
|
|
{
|
|
|
|
|
m_skinMetaAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::SkinMetaAsset>(
|
|
|
|
|
skinMetaAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_skinToSkeletonIndexMap.clear();
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skin and morph target meta assets are ready, fill the runtime mesh data.
|
|
|
|
|
if ((!skinMetaAssetExists || m_skinMetaAsset.IsReady()) &&
|
|
|
|
|
(!morphTargetMetaAssetExists || m_morphTargetMetaAsset.IsReady()))
|
|
|
|
|
if (loadReq == LoadRequirement::RequireBlockingLoad)
|
|
|
|
|
{
|
|
|
|
|
// Optional, not all actors have a skinned meshes.
|
|
|
|
|
if (skinMetaAssetExists)
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LoadMeshAssetsQueued();
|
|
|
|
|
}
|
|
|
|
|
if (m_skinMetaAsset.IsReady())
|
|
|
|
|
{
|
|
|
|
|
m_skinToSkeletonIndexMap = ConstructSkinToSkeletonIndexMap(m_skinMetaAsset);
|
|
|
|
|
}
|
|
|
|
|
ConstructMeshes();
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|