[ATOM-14477] Add clone function to model and/or model asset (#135)

* Added clone methods for the buffer, model lod and model assets.
* Cloning works via the creators.
* Mesh handle/instance now knows about the model asset it originated from as well as the cloned model asset that we need for instancing until instancing works without the dependencies to the asset ids.
* MeshComponentRequestBus returns the original asset id and the model asset. If you need access to the clone, go by the model.
* Cloth component mesh now gettings its model asset from the model as it needs to work on the clone.
* Moved the requires cloning function from the mesh loader in the mesh feature processor to the mesh component controller.
* As we need the model asset to be loaded before we can check if it requires cloning or not, we couldn't pass in a bool from the controller but had to use a callback.
* Using asset hint instead of asset id for the model lod asset creator error.
* Storing a map of source buffer asset ids and the actual cloned buffer assets rather than just their ids.
* Using the buffer assets from the new map directly and removed the search process in the mesh loop where the asset views are created.
* Fixed the vegetation mocks.
* Using the actor's mesh asset when emitting the on model ready event for the mesh component notification bus.
* Mesh components notifications connection policy changed to adapt to cloned model asset.
* Handling empty meshes in model lod asset creator.
* Removed the requires cloning callback from the mesh feature processor and made it a parameter to the acquire mesh function
* Fixing mocks and unit tests
This commit is contained in:
Benjamin Jillich
2021-04-23 18:33:00 +02:00
committed by GitHub
parent e772afa06e
commit 0fa00a117c
18 changed files with 651 additions and 288 deletions
@@ -21,6 +21,8 @@
#include <Atom/RPI.Public/Culling.h>
#include <Atom/Utils/StableDynamicArray.h>
#include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AzCore/Console/IConsole.h>
@@ -150,7 +152,8 @@ namespace AZ
const Data::Asset<RPI::ModelAsset>& modelAsset,
const MaterialAssignmentMap& materials,
bool skinnedMeshWithMotion,
bool rayTracingEnabled)
bool rayTracingEnabled,
RequiresCloneCallback requiresCloneCallback)
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
@@ -166,8 +169,9 @@ namespace AZ
meshDataHandle->m_scene = GetParentScene();
meshDataHandle->m_materialAssignments = materials;
meshDataHandle->m_objectId = m_transformService->ReserveObjectId();
meshDataHandle->m_originalModelAsset = modelAsset;
meshDataHandle->m_requiresCloningCallback = requiresCloneCallback;
meshDataHandle->m_meshLoader = AZStd::make_unique<MeshDataInstance::MeshLoader>(modelAsset, &*meshDataHandle);
return meshDataHandle;
@@ -177,13 +181,14 @@ namespace AZ
const Data::Asset<RPI::ModelAsset>& modelAsset,
const Data::Instance<RPI::Material>& material,
bool skinnedMeshWithMotion,
bool rayTracingEnabled)
bool rayTracingEnabled,
RequiresCloneCallback requiresCloneCallback)
{
Render::MaterialAssignmentMap materials;
Render::MaterialAssignment& defaultMaterial = materials[AZ::Render::DefaultMaterialAssignmentId];
defaultMaterial.m_materialInstance = material;
return AcquireMesh(modelAsset, materials, skinnedMeshWithMotion, rayTracingEnabled);
return AcquireMesh(modelAsset, materials, skinnedMeshWithMotion, rayTracingEnabled, requiresCloneCallback);
}
bool MeshFeatureProcessor::ReleaseMesh(MeshHandle& meshHandle)
@@ -205,7 +210,7 @@ namespace AZ
{
if (meshHandle.IsValid())
{
MeshHandle clone = AcquireMesh(meshHandle->m_model->GetModelAsset(), meshHandle->m_materialAssignments);
MeshHandle clone = AcquireMesh(meshHandle->m_originalModelAsset, meshHandle->m_materialAssignments);
return clone;
}
return MeshFeatureProcessor::MeshHandle();
@@ -216,6 +221,16 @@ namespace AZ
return meshHandle.IsValid() ? meshHandle->m_model : nullptr;
}
Data::Asset<RPI::ModelAsset> MeshFeatureProcessor::GetModelAsset(const MeshHandle& meshHandle) const
{
if (meshHandle.IsValid())
{
return meshHandle->m_originalModelAsset;
}
return {};
}
void MeshFeatureProcessor::SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance<RPI::Material>& material)
{
Render::MaterialAssignmentMap materials;
@@ -430,7 +445,6 @@ namespace AZ
}
// MeshDataInstance::MeshLoader...
MeshDataInstance::MeshLoader::MeshLoader(const Data::Asset<RPI::ModelAsset>& modelAsset, MeshDataInstance* parent)
: m_modelAsset(modelAsset)
, m_parent(parent)
@@ -443,10 +457,13 @@ namespace AZ
return;
}
// Check if the model is in the instance database
// Check if the model is in the instance database and skip the loading process in this case.
// The model asset id is used as instance id to indicate that it is a static and shared.
Data::Instance<RPI::Model> model = Data::InstanceDatabase<RPI::Model>::Instance().Find(Data::InstanceId::CreateFromAssetId(m_modelAsset.GetId()));
if (model)
{
// In case the mesh asset requires instancing (e.g. when containing a cloth buffer), the model will always be cloned and there will not be a
// model instance with the asset id as instance id as searched above.
m_parent->Init(model);
m_modelChangedEvent.Signal(AZStd::move(model));
return;
@@ -470,8 +487,35 @@ namespace AZ
void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
Data::Asset<RPI::ModelAsset> modelAsset = asset;
Data::Instance<RPI::Model> model = RPI::Model::FindOrCreate(asset);
// Assign the fully loaded asset back to the mesh handle to not only hold asset id, but the actual data as well.
m_parent->m_originalModelAsset = asset;
Data::Instance<RPI::Model> model;
// Check if a requires cloning callback got set and if so check if cloning the model asset is requested.
if (m_parent->m_requiresCloningCallback &&
m_parent->m_requiresCloningCallback(modelAsset))
{
// Clone the model asset to force create another model instance.
AZ::Data::AssetId newId(AZ::Uuid::CreateRandom(), /*subId=*/0);
Data::Asset<RPI::ModelAsset> clonedAsset;
if (AZ::RPI::ModelAssetCreator::Clone(modelAsset, clonedAsset, newId))
{
model = RPI::Model::FindOrCreate(clonedAsset);
}
else
{
AZ_Error("MeshDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr());
model = RPI::Model::FindOrCreate(modelAsset);
}
}
else
{
// Static mesh, no cloth buffer present.
model = RPI::Model::FindOrCreate(modelAsset);
}
if (model)
{
m_parent->Init(model);