Integrating github/staging through commit ab87ed9
This commit is contained in:
@@ -31,9 +31,9 @@ ly_add_target(
|
||||
PUBLIC
|
||||
3rdParty::NvCloth
|
||||
Gem::LmbrCentral
|
||||
Gem::AtomLyIntegration_CommonFeatures.Static
|
||||
PRIVATE
|
||||
Gem::EMotionFXStaticLib
|
||||
Gem::AtomLyIntegration_CommonFeatures.Static
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
|
||||
@@ -56,18 +56,23 @@ namespace NvCloth
|
||||
return;
|
||||
}
|
||||
|
||||
LmbrCentral::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
}
|
||||
|
||||
void ClothComponent::Deactivate()
|
||||
{
|
||||
LmbrCentral::MeshComponentNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Render::MeshComponentNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
m_clothComponentMesh.reset();
|
||||
}
|
||||
|
||||
void ClothComponent::OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset)
|
||||
void ClothComponent::OnModelReady(
|
||||
const AZ::Data::Asset<AZ::RPI::ModelAsset>& asset,
|
||||
[[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
|
||||
{
|
||||
// [TODO LYN-1886] Remove this call once OnModelDestroyed is part of MeshComponentNotificationBus
|
||||
OnModelDestroyed();
|
||||
|
||||
if (!asset.IsReady())
|
||||
{
|
||||
return;
|
||||
@@ -76,7 +81,7 @@ namespace NvCloth
|
||||
m_clothComponentMesh = AZStd::make_unique<ClothComponentMesh>(GetEntityId(), m_config);
|
||||
}
|
||||
|
||||
void ClothComponent::OnMeshDestroyed()
|
||||
void ClothComponent::OnModelDestroyed()
|
||||
{
|
||||
m_clothComponentMesh.reset();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
|
||||
#include <LmbrCentral/Rendering/MeshComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
|
||||
#include <Components/ClothConfiguration.h>
|
||||
#include <Components/ClothComponentMesh/ClothComponentMesh.h>
|
||||
@@ -24,7 +24,7 @@ namespace NvCloth
|
||||
//! Class for runtime Cloth Component.
|
||||
class ClothComponent
|
||||
: public AZ::Component
|
||||
, public LmbrCentral::MeshComponentNotificationBus::Handler
|
||||
, public AZ::Render::MeshComponentNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ClothComponent, "{AC9B8FA0-A6DA-4377-8219-25BA7E4A22E9}");
|
||||
@@ -46,9 +46,9 @@ namespace NvCloth
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
// LmbrCentral::MeshComponentNotificationBus::Handler overrides ...
|
||||
void OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset) override;
|
||||
void OnMeshDestroyed() override;
|
||||
// AZ::Render::MeshComponentNotificationBus::Handler overrides ...
|
||||
void OnModelReady(const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, const AZ::Data::Instance<AZ::RPI::Model>& model) override;
|
||||
void OnModelDestroyed(); // [TODO LYN-1886] Add override once it's part of MeshComponentNotificationBus
|
||||
|
||||
private:
|
||||
ClothConfiguration m_config;
|
||||
|
||||
@@ -387,9 +387,14 @@ namespace NvCloth
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Cloth);
|
||||
|
||||
if (!m_cloth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate normals of the cloth particles (simplified mesh).
|
||||
AZStd::vector<AZ::Vector3> normals;
|
||||
bool normalsCalculated =
|
||||
[[maybe_unused]] bool normalsCalculated =
|
||||
AZ::Interface<ITangentSpaceHelper>::Get()->CalculateNormals(particles, m_cloth->GetInitialIndices(), normals);
|
||||
AZ_Assert(normalsCalculated, "Cloth component mesh failed to calculate normals.");
|
||||
|
||||
@@ -416,7 +421,7 @@ namespace NvCloth
|
||||
}
|
||||
|
||||
// Calculate tangents and bitangents for the full mesh.
|
||||
bool tangentsAndBitangentsCalculated =
|
||||
[[maybe_unused]] bool tangentsAndBitangentsCalculated =
|
||||
AZ::Interface<ITangentSpaceHelper>::Get()->CalculateTangentsAndBitagents(
|
||||
renderData.m_particles, m_meshClothInfo.m_indices,
|
||||
m_meshClothInfo.m_uvs, renderData.m_normals,
|
||||
@@ -444,9 +449,9 @@ namespace NvCloth
|
||||
const auto& renderBitangents = renderData.m_bitangents;
|
||||
|
||||
AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset;
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(modelAsset, m_entityId,
|
||||
&AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
|
||||
if (!modelAsset.GetId().IsValid())
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(
|
||||
modelAsset, m_entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
|
||||
if (!modelAsset.IsReady())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ namespace NvCloth
|
||||
|
||||
void UpdateConfiguration(AZ::EntityId entityId, const ClothConfiguration& config);
|
||||
|
||||
void CopyRenderDataToModel();
|
||||
|
||||
protected:
|
||||
// Functions used to setup and tear down cloth component mesh
|
||||
void Setup(AZ::EntityId entityId, const ClothConfiguration& config);
|
||||
@@ -85,7 +87,6 @@ namespace NvCloth
|
||||
void UpdateSimulationSkinning();
|
||||
void UpdateSimulationConstraints();
|
||||
void UpdateRenderData(const AZStd::vector<SimParticleFormat>& particles);
|
||||
void CopyRenderDataToModel();
|
||||
|
||||
bool CreateCloth();
|
||||
void ApplyConfigurationToCloth();
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace NvCloth
|
||||
|
||||
if (!m_separationConstraints.empty())
|
||||
{
|
||||
bool normalsCalculated = AZ::Interface<ITangentSpaceHelper>::Get()->CalculateNormals(simParticles, simIndices, m_normals);
|
||||
[[maybe_unused]] bool normalsCalculated = AZ::Interface<ITangentSpaceHelper>::Get()->CalculateNormals(simParticles, simIndices, m_normals);
|
||||
AZ_Assert(normalsCalculated, "Cloth constraints failed to calculate normals.");
|
||||
|
||||
CalculateSeparationConstraints();
|
||||
|
||||
@@ -434,20 +434,25 @@ namespace NvCloth
|
||||
{
|
||||
AzToolsFramework::Components::EditorComponentBase::Activate();
|
||||
|
||||
LmbrCentral::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
}
|
||||
|
||||
void EditorClothComponent::Deactivate()
|
||||
{
|
||||
LmbrCentral::MeshComponentNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Render::MeshComponentNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
AzToolsFramework::Components::EditorComponentBase::Deactivate();
|
||||
|
||||
m_clothComponentMesh.reset();
|
||||
}
|
||||
|
||||
void EditorClothComponent::OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset)
|
||||
void EditorClothComponent::OnModelReady(
|
||||
const AZ::Data::Asset<AZ::RPI::ModelAsset>& asset,
|
||||
[[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
|
||||
{
|
||||
// [TODO LYN-1886] Remove this call once OnModelDestroyed is part of MeshComponentNotificationBus
|
||||
OnModelDestroyed();
|
||||
|
||||
if (!asset.IsReady())
|
||||
{
|
||||
return;
|
||||
@@ -513,7 +518,7 @@ namespace NvCloth
|
||||
AzToolsFramework::Refresh_EntireTree);
|
||||
}
|
||||
|
||||
void EditorClothComponent::OnMeshDestroyed()
|
||||
void EditorClothComponent::OnModelDestroyed()
|
||||
{
|
||||
m_previousMeshNode = m_config.m_meshNode;
|
||||
|
||||
@@ -537,21 +542,17 @@ namespace NvCloth
|
||||
|
||||
AZ::u32 EditorClothComponent::OnSimulatedInEditorToggled()
|
||||
{
|
||||
m_clothComponentMesh.reset();
|
||||
|
||||
m_simulateInEditor = !m_simulateInEditor;
|
||||
|
||||
if (m_simulateInEditor)
|
||||
{
|
||||
m_clothComponentMesh = AZStd::make_unique<ClothComponentMesh>(GetEntityId(), m_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Force MeshComponent to reload current mesh asset in order to restore original mesh
|
||||
AZ::Data::Asset<AZ::Data::AssetData> meshAsset;
|
||||
LmbrCentral::MeshComponentRequestBus::EventResult(meshAsset, GetEntityId(), &LmbrCentral::MeshComponentRequests::GetMeshAsset);
|
||||
m_clothComponentMesh = AZStd::make_unique<ClothComponentMesh>(GetEntityId(), m_config);
|
||||
|
||||
LmbrCentral::MeshComponentRequestBus::Event(GetEntityId(), &LmbrCentral::MeshComponentRequests::SetMeshAsset, meshAsset.GetId());
|
||||
if (!m_simulateInEditor)
|
||||
{
|
||||
// Since the instance was just created this will restore the model
|
||||
// to its original position before cloth simulation.
|
||||
m_clothComponentMesh->CopyRenderDataToModel();
|
||||
|
||||
m_clothComponentMesh.reset();
|
||||
}
|
||||
|
||||
return AZ::Edit::PropertyRefreshLevels::None;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
|
||||
#include <LmbrCentral/Rendering/MeshComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
|
||||
#include <Components/ClothConfiguration.h>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace NvCloth
|
||||
//! Class for in-editor Cloth Component.
|
||||
class EditorClothComponent
|
||||
: public AzToolsFramework::Components::EditorComponentBase
|
||||
, public LmbrCentral::MeshComponentNotificationBus::Handler
|
||||
, public AZ::Render::MeshComponentNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_EDITOR_COMPONENT(EditorClothComponent, "{2C99B4EF-8A5F-4585-89F9-86D50754DF7E}", AzToolsFramework::Components::EditorComponentBase);
|
||||
@@ -50,9 +50,9 @@ namespace NvCloth
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
// LmbrCentral::MeshComponentNotificationBus::Handler overrides ...
|
||||
void OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset) override;
|
||||
void OnMeshDestroyed() override;
|
||||
// AZ::Render::MeshComponentNotificationBus::Handler overrides ...
|
||||
void OnModelReady(const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, const AZ::Data::Instance<AZ::RPI::Model>& model) override;
|
||||
void OnModelDestroyed(); // [TODO LYN-1886] Add override once it's part of MeshComponentNotificationBus
|
||||
|
||||
private:
|
||||
bool IsSimulatedInEditor() const;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
|
||||
#include <LmbrCentral/Rendering/MeshComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
|
||||
#include <Editor/PropertyTypes.h>
|
||||
#include <Editor/MeshNodeHandler.h>
|
||||
@@ -120,10 +120,10 @@ namespace NvCloth
|
||||
|
||||
AZ::Data::Asset<AZ::Data::AssetData> MeshNodeHandler::GetMeshAsset(const AZ::EntityId entityId) const
|
||||
{
|
||||
AZ::Data::Asset<AZ::Data::AssetData> meshAsset;
|
||||
LmbrCentral::MeshComponentRequestBus::EventResult(
|
||||
meshAsset, entityId, &LmbrCentral::MeshComponentRequestBus::Events::GetMeshAsset);
|
||||
return meshAsset;
|
||||
AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset;
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(
|
||||
modelAsset, entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
|
||||
return modelAsset;
|
||||
}
|
||||
} // namespace Editor
|
||||
} // namespace NvCloth
|
||||
|
||||
@@ -434,7 +434,7 @@ namespace NvCloth
|
||||
m_factory->Init();
|
||||
|
||||
// Create Default Solver
|
||||
ISolver* solver = FindOrCreateSolver(DefaultSolverName);
|
||||
[[maybe_unused]] ISolver* solver = FindOrCreateSolver(DefaultSolverName);
|
||||
AZ_Assert(solver, "Error: Default solver failed to be created");
|
||||
|
||||
AZ::Interface<IClothSystem>::Register(this);
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
#include <Utils/MeshAssetHelper.h>
|
||||
#include <Utils/ActorAssetHelper.h>
|
||||
|
||||
#include <platform.h> // Needed for MeshAsset.h
|
||||
#include <LmbrCentral/Rendering/MeshComponentBus.h>
|
||||
#include <LmbrCentral/Rendering/MeshAsset.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
|
||||
#include <Integration/ActorComponentBus.h>
|
||||
|
||||
@@ -41,16 +39,10 @@ namespace NvCloth
|
||||
return AZStd::make_unique<ActorAssetHelper>(entityId);
|
||||
}
|
||||
|
||||
AZ::Data::Asset<AZ::Data::AssetData> meshAsset;
|
||||
LmbrCentral::MeshComponentRequestBus::EventResult(
|
||||
meshAsset, entityId, &LmbrCentral::MeshComponentRequestBus::Events::GetMeshAsset);
|
||||
if (!meshAsset)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Does the entity have a Mesh Asset?
|
||||
if (meshAsset.GetType() == AZ::AzTypeInfo<LmbrCentral::MeshAsset>::Uuid())
|
||||
AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset;
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(
|
||||
modelAsset, entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
|
||||
if (modelAsset.GetId().IsValid())
|
||||
{
|
||||
return AZStd::make_unique<MeshAssetHelper>(entityId);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NvCloth
|
||||
//! While the simulation data is a single buffer for vertices and indices,
|
||||
//! this structure knows how to separate them in different submeshes, this will be
|
||||
//! be used when the MeshModificationNotificationBus request the modification
|
||||
//! of an specific submesh (lodLevel and primitiveIndex).
|
||||
//! of a specific submesh (lodLevel and primitiveIndex).
|
||||
struct MeshNodeInfo
|
||||
{
|
||||
//! LOD level of the mesh node inside the asset.
|
||||
|
||||
@@ -10,14 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <platform.h> // Needed for MeshAsset.h
|
||||
#include <LmbrCentral/Rendering/MeshComponentBus.h>
|
||||
#include <LmbrCentral/Rendering/MeshAsset.h>
|
||||
#include <IRenderer.h>
|
||||
|
||||
#include <IIndexedMesh.h> // Needed for SMeshColor
|
||||
|
||||
#include <AzCore/Math/Color.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
|
||||
#include <Utils/MeshAssetHelper.h>
|
||||
|
||||
@@ -30,36 +23,44 @@ namespace NvCloth
|
||||
|
||||
void MeshAssetHelper::GatherClothMeshNodes(MeshNodeList& meshNodes)
|
||||
{
|
||||
AZ::Data::Asset<LmbrCentral::MeshAsset> meshAsset;
|
||||
LmbrCentral::MeshComponentRequestBus::EventResult(
|
||||
meshAsset, m_entityId, &LmbrCentral::MeshComponentRequestBus::Events::GetMeshAsset);
|
||||
if (!meshAsset.IsReady())
|
||||
AZ::Data::Asset<AZ::RPI::ModelAsset> modelDataAsset;
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(
|
||||
modelDataAsset, m_entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
|
||||
if (!modelDataAsset.IsReady())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IStatObj* statObj = meshAsset.Get()->m_statObj.get();
|
||||
if (!statObj)
|
||||
const AZ::RPI::ModelAsset* modelAsset = modelDataAsset.Get();
|
||||
if (!modelAsset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!statObj->GetClothData().empty())
|
||||
{
|
||||
meshNodes.push_back(statObj->GetCGFNodeName().c_str());
|
||||
}
|
||||
const auto lodAssets = modelAsset->GetLodAssets();
|
||||
|
||||
const int subObjectCount = statObj->GetSubObjectCount();
|
||||
for (int i = 0; i < subObjectCount; ++i)
|
||||
AZStd::set<AZStd::string> meshNodeNames;
|
||||
|
||||
if (!lodAssets.empty())
|
||||
{
|
||||
IStatObj::SSubObject* subObject = statObj->GetSubObject(i);
|
||||
if (subObject &&
|
||||
subObject->pStatObj &&
|
||||
!subObject->pStatObj->GetClothData().empty())
|
||||
const int lodLevel = 0;
|
||||
|
||||
if (const AZ::RPI::ModelLodAsset* lodAsset = lodAssets[lodLevel].Get())
|
||||
{
|
||||
meshNodes.push_back(subObject->pStatObj->GetCGFNodeName().c_str());
|
||||
const auto meshes = lodAsset->GetMeshes();
|
||||
|
||||
for (const auto& mesh : meshes)
|
||||
{
|
||||
const bool hasClothData = (mesh.GetSemanticBufferAssetView(AZ::Name("CLOTH_DATA")) != nullptr);
|
||||
if (hasClothData)
|
||||
{
|
||||
meshNodeNames.insert(mesh.GetName().GetStringView());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
meshNodes.assign(meshNodeNames.begin(), meshNodeNames.end());
|
||||
}
|
||||
|
||||
bool MeshAssetHelper::ObtainClothMeshNodeInfo(
|
||||
@@ -69,164 +70,158 @@ namespace NvCloth
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Cloth);
|
||||
|
||||
AZ::Data::Asset<LmbrCentral::MeshAsset> meshAsset;
|
||||
LmbrCentral::MeshComponentRequestBus::EventResult(
|
||||
meshAsset, m_entityId, &LmbrCentral::MeshComponentRequestBus::Events::GetMeshAsset);
|
||||
if (!meshAsset.IsReady())
|
||||
AZ::Data::Asset<AZ::RPI::ModelAsset> modelDataAsset;
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(
|
||||
modelDataAsset, m_entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
|
||||
if (!modelDataAsset.IsReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IStatObj* statObj = meshAsset.Get()->m_statObj.get();
|
||||
if (!statObj)
|
||||
const AZ::RPI::ModelAsset* modelAsset = modelDataAsset.Get();
|
||||
if (!modelAsset)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IStatObj* selectedStatObj = nullptr;
|
||||
int primitiveIndex = 0;
|
||||
const auto lodAssets = modelAsset->GetLodAssets();
|
||||
|
||||
// Find the render data of the mesh node
|
||||
if (meshNode == statObj->GetCGFNodeName().c_str())
|
||||
AZStd::vector<const AZ::RPI::ModelLodAsset::Mesh*> meshNodes;
|
||||
AZStd::vector<size_t> meshPrimitiveIndices;
|
||||
|
||||
if(!lodAssets.empty())
|
||||
{
|
||||
selectedStatObj = statObj;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int subObjectCount = statObj->GetSubObjectCount();
|
||||
for (int i = 0; i < subObjectCount; ++i)
|
||||
const int lodLevel = 0;
|
||||
|
||||
if (const AZ::RPI::ModelLodAsset* lodAsset = lodAssets[lodLevel].Get())
|
||||
{
|
||||
IStatObj::SSubObject* subObject = statObj->GetSubObject(i);
|
||||
if (subObject &&
|
||||
subObject->pStatObj &&
|
||||
subObject->pStatObj->GetRenderMesh() &&
|
||||
meshNode == subObject->pStatObj->GetCGFNodeName().c_str())
|
||||
const auto meshes = lodAsset->GetMeshes();
|
||||
|
||||
for (size_t meshIndex = 0; meshIndex < meshes.size(); ++meshIndex)
|
||||
{
|
||||
selectedStatObj = subObject->pStatObj;
|
||||
primitiveIndex = i;
|
||||
break;
|
||||
if (meshNode == meshes[meshIndex].GetName().GetStringView())
|
||||
{
|
||||
meshNodes.push_back(&meshes[meshIndex]);
|
||||
meshPrimitiveIndices.push_back(meshIndex);
|
||||
meshNodeInfo.m_lodLevel = lodLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool infoObtained = false;
|
||||
|
||||
if (selectedStatObj)
|
||||
if (!meshNodes.empty())
|
||||
{
|
||||
bool dataCopied = false;
|
||||
|
||||
if (IRenderMesh* renderMesh = selectedStatObj->GetRenderMesh())
|
||||
{
|
||||
dataCopied = CopyDataFromRenderMesh(
|
||||
*renderMesh, selectedStatObj->GetClothData(),
|
||||
meshClothInfo);
|
||||
}
|
||||
bool dataCopied = CopyDataFromMeshes(meshNodes, meshClothInfo);
|
||||
|
||||
if (dataCopied)
|
||||
{
|
||||
// subStatObj contains the buffers for all its submeshes
|
||||
// so only 1 submesh is necessary.
|
||||
MeshNodeInfo::SubMesh subMesh;
|
||||
subMesh.m_primitiveIndex = primitiveIndex;
|
||||
subMesh.m_verticesFirstIndex = 0;
|
||||
subMesh.m_numVertices = meshClothInfo.m_particles.size();
|
||||
subMesh.m_indicesFirstIndex = 0;
|
||||
subMesh.m_numIndices = meshClothInfo.m_indices.size();
|
||||
const size_t numSubMeshes = meshNodes.size();
|
||||
|
||||
meshNodeInfo.m_lodLevel = 0; // Cloth is alway in LOD 0
|
||||
meshNodeInfo.m_subMeshes.push_back(subMesh);
|
||||
meshNodeInfo.m_subMeshes.reserve(meshNodes.size());
|
||||
|
||||
int firstVertex = 0;
|
||||
int firstIndex = 0;
|
||||
for (size_t subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex)
|
||||
{
|
||||
MeshNodeInfo::SubMesh subMesh;
|
||||
subMesh.m_primitiveIndex = static_cast<int>(meshPrimitiveIndices[subMeshIndex]);
|
||||
subMesh.m_verticesFirstIndex = firstVertex;
|
||||
subMesh.m_numVertices = static_cast<int>(meshNodes[subMeshIndex]->GetVertexCount());
|
||||
subMesh.m_indicesFirstIndex = firstIndex;
|
||||
subMesh.m_numIndices = static_cast<int>(meshNodes[subMeshIndex]->GetIndexCount());
|
||||
|
||||
firstVertex += subMesh.m_numVertices;
|
||||
firstIndex += subMesh.m_numIndices;
|
||||
|
||||
meshNodeInfo.m_subMeshes.push_back(AZStd::move(subMesh));
|
||||
}
|
||||
|
||||
infoObtained = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("MeshAssetHelper", false, "Failed to extract data from node %s in mesh %s",
|
||||
meshNode.c_str(), statObj->GetFileName().c_str());
|
||||
AZ_Error("MeshAssetHelper", false, "Failed to extract data from node %s in model %s",
|
||||
meshNode.c_str(), modelDataAsset.GetHint().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return infoObtained;
|
||||
}
|
||||
|
||||
bool MeshAssetHelper::CopyDataFromRenderMesh(
|
||||
IRenderMesh& renderMesh,
|
||||
const AZStd::vector<SMeshColor>& renderMeshClothData,
|
||||
bool MeshAssetHelper::CopyDataFromMeshes(
|
||||
const AZStd::vector<const AZ::RPI::ModelLodAsset::Mesh*>& meshes,
|
||||
MeshClothInfo& meshClothInfo)
|
||||
{
|
||||
const int numVertices = renderMesh.GetNumVerts();
|
||||
const int numIndices = renderMesh.GetNumInds();
|
||||
if (numVertices == 0 || numIndices == 0)
|
||||
uint32_t numTotalVertices = 0;
|
||||
uint32_t numTotalIndices = 0;
|
||||
for (const auto* mesh : meshes)
|
||||
{
|
||||
numTotalVertices += mesh->GetVertexCount();
|
||||
numTotalIndices += mesh->GetIndexCount();
|
||||
}
|
||||
if (numTotalVertices == 0 || numTotalIndices == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (numVertices != renderMeshClothData.size())
|
||||
|
||||
meshClothInfo.m_particles.reserve(numTotalVertices);
|
||||
meshClothInfo.m_uvs.reserve(numTotalVertices);
|
||||
meshClothInfo.m_motionConstraints.reserve(numTotalVertices);
|
||||
meshClothInfo.m_backstopData.reserve(numTotalVertices);
|
||||
meshClothInfo.m_indices.reserve(numTotalIndices);
|
||||
|
||||
struct Vec2
|
||||
{
|
||||
AZ_Error("MeshAssetHelper", false,
|
||||
"Number of vertices (%d) doesn't match the number of cloth data (%zu)",
|
||||
numVertices,
|
||||
renderMeshClothData.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
float x, y;
|
||||
};
|
||||
struct Vec3
|
||||
{
|
||||
IRenderMesh::ThreadAccessLock lockRenderMesh(&renderMesh);
|
||||
float x, y, z;
|
||||
};
|
||||
struct Vec4
|
||||
{
|
||||
float x, y, z, w;
|
||||
};
|
||||
const SimUVType uvZero(0.0f, 0.0f);
|
||||
|
||||
vtx_idx* renderMeshIndices = nullptr;
|
||||
strided_pointer<Vec3> renderMeshVertices;
|
||||
strided_pointer<Vec2> renderMeshUVs;
|
||||
for (const auto* mesh : meshes)
|
||||
{
|
||||
const auto sourceIndices = mesh->GetIndexBufferTyped<uint32_t>();
|
||||
const auto sourcePositions = mesh->GetSemanticBufferTyped<Vec3>(AZ::Name("POSITION"));
|
||||
const auto sourceClothData = mesh->GetSemanticBufferTyped<Vec4>(AZ::Name("CLOTH_DATA"));
|
||||
const auto sourceUVs = mesh->GetSemanticBufferTyped<Vec2>(AZ::Name("UV"));
|
||||
|
||||
renderMeshIndices = renderMesh.GetIndexPtr(FSL_READ);
|
||||
renderMeshVertices.data = reinterpret_cast<Vec3*>(renderMesh.GetPosPtr(renderMeshVertices.iStride, FSL_READ));
|
||||
renderMeshUVs.data = reinterpret_cast<Vec2*>(renderMesh.GetUVPtr(renderMeshUVs.iStride, FSL_READ, 0)); // first UV set
|
||||
|
||||
const SimUVType uvZero(0.0f, 0.0f);
|
||||
|
||||
meshClothInfo.m_particles.resize_no_construct(numVertices);
|
||||
meshClothInfo.m_uvs.resize_no_construct(numVertices);
|
||||
meshClothInfo.m_motionConstraints.resize_no_construct(numVertices);
|
||||
meshClothInfo.m_backstopData.resize_no_construct(numVertices);
|
||||
for (int index = 0; index < numVertices; ++index)
|
||||
if (sourceIndices.empty() || sourcePositions.empty() || sourceClothData.empty())
|
||||
{
|
||||
const ColorB clothVertexDataColorB = renderMeshClothData[index].GetRGBA();
|
||||
const AZ::Color clothVertexData(
|
||||
clothVertexDataColorB.r,
|
||||
clothVertexDataColorB.g,
|
||||
clothVertexDataColorB.b,
|
||||
clothVertexDataColorB.a);
|
||||
return false;
|
||||
}
|
||||
|
||||
const float inverseMass = clothVertexData.GetR();
|
||||
const float motionConstraint = clothVertexData.GetG();
|
||||
const float backstopRadius = clothVertexData.GetA();
|
||||
const float backstopOffset = ConvertBackstopOffset(clothVertexData.GetB());
|
||||
const uint32_t numVertices = mesh->GetVertexCount();
|
||||
for (uint32_t index = 0; index < numVertices; ++index)
|
||||
{
|
||||
const float inverseMass = sourceClothData[index].x;
|
||||
const float motionConstraint = sourceClothData[index].y;
|
||||
const float backstopOffset = ConvertBackstopOffset(sourceClothData[index].z);
|
||||
const float backstopRadius = sourceClothData[index].w;
|
||||
|
||||
meshClothInfo.m_particles[index].Set(
|
||||
renderMeshVertices[index].x,
|
||||
renderMeshVertices[index].y,
|
||||
renderMeshVertices[index].z,
|
||||
meshClothInfo.m_particles.emplace_back(
|
||||
sourcePositions[index].x,
|
||||
sourcePositions[index].y,
|
||||
sourcePositions[index].z,
|
||||
inverseMass);
|
||||
|
||||
meshClothInfo.m_motionConstraints[index] = motionConstraint;
|
||||
meshClothInfo.m_backstopData[index].Set(backstopOffset, backstopRadius);
|
||||
meshClothInfo.m_motionConstraints.emplace_back(motionConstraint);
|
||||
meshClothInfo.m_backstopData.emplace_back(backstopOffset, backstopRadius);
|
||||
|
||||
meshClothInfo.m_uvs[index] = (renderMeshUVs.data) ? SimUVType(renderMeshUVs[index].x, renderMeshUVs[index].y) : uvZero;
|
||||
meshClothInfo.m_uvs.emplace_back(
|
||||
sourceUVs.empty()
|
||||
? uvZero
|
||||
: SimUVType(sourceUVs[index].x, sourceUVs[index].y));
|
||||
}
|
||||
|
||||
meshClothInfo.m_indices.resize_no_construct(numIndices);
|
||||
// Fast copy when SimIndexType is the same size as the vtx_idx.
|
||||
if constexpr (sizeof(SimIndexType) == sizeof(vtx_idx))
|
||||
{
|
||||
memcpy(meshClothInfo.m_indices.data(), renderMeshIndices, numIndices * sizeof(SimIndexType));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < numIndices; ++index)
|
||||
{
|
||||
meshClothInfo.m_indices[index] = static_cast<SimIndexType>(renderMeshIndices[index]);
|
||||
}
|
||||
}
|
||||
|
||||
renderMesh.UnlockStream(VSF_GENERAL);
|
||||
renderMesh.UnlockIndexStream();
|
||||
meshClothInfo.m_indices.insert(meshClothInfo.m_indices.end(), sourceIndices.begin(), sourceIndices.end());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Utils/AssetHelper.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelLodAsset.h>
|
||||
|
||||
struct IRenderMesh;
|
||||
struct SMeshColor;
|
||||
#include <Utils/AssetHelper.h>
|
||||
|
||||
namespace NvCloth
|
||||
{
|
||||
@@ -40,9 +39,8 @@ namespace NvCloth
|
||||
}
|
||||
|
||||
private:
|
||||
bool CopyDataFromRenderMesh(
|
||||
IRenderMesh& renderMesh,
|
||||
const AZStd::vector<SMeshColor>& renderMeshClothData,
|
||||
bool CopyDataFromMeshes(
|
||||
const AZStd::vector<const AZ::RPI::ModelLodAsset::Mesh*>& meshes,
|
||||
MeshClothInfo& meshClothInfo);
|
||||
};
|
||||
} // namespace NvCloth
|
||||
|
||||
@@ -367,7 +367,6 @@ namespace UnitTest
|
||||
const AZStd::vector<NvCloth::SphereCollider>& sphereColliders = actorClothColliders->GetSphereColliders();
|
||||
const AZStd::vector<AZ::Vector4>& nativeSpheres = actorClothColliders->GetSpheres();
|
||||
const AZStd::vector<NvCloth::CapsuleCollider>& capsuleColliders = actorClothColliders->GetCapsuleColliders();
|
||||
const AZStd::vector<uint32_t>& nativeCapsuleIndices = actorClothColliders->GetCapsuleIndices();
|
||||
|
||||
EXPECT_THAT(sphereColliders[0].m_offsetTransform, IsCloseTolerance(sphereColliderOffet, Tolerance));
|
||||
EXPECT_THAT(sphereColliders[0].m_currentModelSpaceTransform, IsCloseTolerance(newJointRootTransform * sphereColliderOffet, Tolerance));
|
||||
|
||||
@@ -420,7 +420,10 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// [TODO LYN-1887] Revisit when Cloth Component Mesh works with Atom models
|
||||
// [TODO LYN-1891]
|
||||
// Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
|
||||
// At the moment, CreateAssetFromActor fills only Actor to the ActorAsset, but not the RenderActor,
|
||||
// because of that the AtomModel is not created and OnModelReady is not called.
|
||||
TEST_F(NvClothComponentMesh, DISABLED_ClothComponentMesh_ModifyMesh_RenderMeshIsUpdated)
|
||||
{
|
||||
{
|
||||
|
||||
@@ -79,13 +79,13 @@ namespace UnitTest
|
||||
|
||||
bool NvClothComponent::IsConnectedToMeshComponentNotificationBus(NvCloth::ClothComponent* clothComponent) const
|
||||
{
|
||||
return static_cast<LmbrCentral::MeshComponentNotificationBus::Handler*>(clothComponent)->BusIsConnectedId(clothComponent->GetEntityId());
|
||||
return static_cast<AZ::Render::MeshComponentNotificationBus::Handler*>(clothComponent)->BusIsConnectedId(clothComponent->GetEntityId());
|
||||
}
|
||||
|
||||
TEST_F(NvClothComponent, ClothComponent_WithoutDependencies_ReturnsMissingRequiredService)
|
||||
{
|
||||
AZStd::unique_ptr<AZ::Entity> entity = AZStd::make_unique<AZ::Entity>();
|
||||
auto* clothComponent =entity->CreateComponent<NvCloth::ClothComponent>();
|
||||
entity->CreateComponent<NvCloth::ClothComponent>();
|
||||
entity->Init();
|
||||
|
||||
AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails();
|
||||
@@ -145,7 +145,11 @@ namespace UnitTest
|
||||
EXPECT_FALSE(IsConnectedToMeshComponentNotificationBus(clothComponent));
|
||||
}
|
||||
|
||||
TEST_F(NvClothComponent, ClothComponent_WithActorSetup_ReturnsValidClothComponentMesh)
|
||||
// [TODO LYN-1891]
|
||||
// Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
|
||||
// At the moment, CreateAssetFromActor fills only Actor to the ActorAsset, but not the RenderActor,
|
||||
// because of that the AtomModel is not created and OnModelReady is not called.
|
||||
TEST_F(NvClothComponent, DISABLED_ClothComponent_WithActorSetup_ReturnsValidClothComponentMesh)
|
||||
{
|
||||
const AZStd::string meshNodeName = "cloth_mesh_node";
|
||||
|
||||
|
||||
@@ -188,7 +188,11 @@ namespace UnitTest
|
||||
EXPECT_TRUE(meshNodeList[0] == NvCloth::Internal::StatusMessageNoAsset);
|
||||
}
|
||||
|
||||
TEST_F(NvClothEditorClothComponent, EditorClothComponent_OnMeshCreatedWithEmptyActor_ReturnsMeshNodeListWithNoClothMessage)
|
||||
// [TODO LYN-1891]
|
||||
// Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
|
||||
// Editor Cloth component now uses the new AZ::Render::MeshComponentNotificationBus::OnModelReady
|
||||
// notification and this test does not setup a model yet.
|
||||
TEST_F(NvClothEditorClothComponent, DISABLED_EditorClothComponent_OnMeshCreatedWithEmptyActor_ReturnsMeshNodeListWithNoClothMessage)
|
||||
{
|
||||
auto editorEntity = CreateInactiveEditorEntity("ClothComponentEditorEntity");
|
||||
auto* editorClothComponent = editorEntity->CreateComponent<NvCloth::EditorClothComponent>();
|
||||
@@ -208,7 +212,11 @@ namespace UnitTest
|
||||
EXPECT_TRUE(meshNodeList[0] == NvCloth::Internal::StatusMessageNoClothNodes);
|
||||
}
|
||||
|
||||
TEST_F(NvClothEditorClothComponent, EditorClothComponent_OnMeshCreatedWithActorWithoutClothMesh_ReturnsMeshNodeListWithNoClothMessage)
|
||||
// [TODO LYN-1891]
|
||||
// Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
|
||||
// Editor Cloth component now uses the new AZ::Render::MeshComponentNotificationBus::OnModelReady
|
||||
// notification and this test does not setup a model yet.
|
||||
TEST_F(NvClothEditorClothComponent, DISABLED_EditorClothComponent_OnMeshCreatedWithActorWithoutClothMesh_ReturnsMeshNodeListWithNoClothMessage)
|
||||
{
|
||||
auto editorEntity = CreateInactiveEditorEntity("ClothComponentEditorEntity");
|
||||
auto* editorClothComponent = editorEntity->CreateComponent<NvCloth::EditorClothComponent>();
|
||||
@@ -230,7 +238,11 @@ namespace UnitTest
|
||||
EXPECT_TRUE(meshNodeList[0] == NvCloth::Internal::StatusMessageNoClothNodes);
|
||||
}
|
||||
|
||||
TEST_F(NvClothEditorClothComponent, EditorClothComponent_OnMeshCreatedWithActorWithClothMesh_ReturnsValidMeshNodeList)
|
||||
// [TODO LYN-1891]
|
||||
// Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
|
||||
// Editor Cloth component now uses the new AZ::Render::MeshComponentNotificationBus::OnModelReady
|
||||
// notification and this test does not setup a model yet.
|
||||
TEST_F(NvClothEditorClothComponent, DISABLED_EditorClothComponent_OnMeshCreatedWithActorWithClothMesh_ReturnsValidMeshNodeList)
|
||||
{
|
||||
auto editorEntity = CreateInactiveEditorEntity("ClothComponentEditorEntity");
|
||||
auto* editorClothComponent = editorEntity->CreateComponent<NvCloth::EditorClothComponent>();
|
||||
@@ -283,7 +295,11 @@ namespace UnitTest
|
||||
EXPECT_TRUE(meshNodesWithBackstopData.empty());
|
||||
}
|
||||
|
||||
TEST_F(NvClothEditorClothComponent, EditorClothComponent_OnMeshCreatedWithActorWithBackstop_ReturnsValidMeshNodesWithBackstopData)
|
||||
// [TODO LYN-1891]
|
||||
// Revisit when Cloth Component Mesh works with Actors adapted to Atom models.
|
||||
// Editor Cloth component now uses the new AZ::Render::MeshComponentNotificationBus::OnModelReady
|
||||
// notification and this test does not setup a model yet.
|
||||
TEST_F(NvClothEditorClothComponent, DISABLED_EditorClothComponent_OnMeshCreatedWithActorWithBackstop_ReturnsValidMeshNodesWithBackstopData)
|
||||
{
|
||||
auto editorEntity = CreateInactiveEditorEntity("ClothComponentEditorEntity");
|
||||
auto* editorClothComponent = editorEntity->CreateComponent<NvCloth::EditorClothComponent>();
|
||||
@@ -306,7 +322,9 @@ namespace UnitTest
|
||||
EXPECT_TRUE(meshNodesWithBackstopData.find(MeshNodeName) != meshNodesWithBackstopData.end());
|
||||
}
|
||||
|
||||
TEST_F(NvClothEditorClothComponent, EditorClothComponent_OnMeshDestroyed_ReturnsMeshNodeListWithNoAssetMessage)
|
||||
// [TODO LYN-2252]
|
||||
// Enable test once OnModelDestroyed is available.
|
||||
TEST_F(NvClothEditorClothComponent, DISABLED_EditorClothComponent_OnMeshDestroyed_ReturnsMeshNodeListWithNoAssetMessage)
|
||||
{
|
||||
auto editorEntity = CreateInactiveEditorEntity("ClothComponentEditorEntity");
|
||||
auto* editorClothComponent = editorEntity->CreateComponent<NvCloth::EditorClothComponent>();
|
||||
@@ -323,7 +341,7 @@ namespace UnitTest
|
||||
editorActorComponent->SetActorAsset(CreateAssetFromActor(AZStd::move(actor)));
|
||||
}
|
||||
|
||||
editorClothComponent->OnMeshDestroyed();
|
||||
//editorClothComponent->OnModelDestroyed();
|
||||
|
||||
const NvCloth::MeshNodeList& meshNodeList = editorClothComponent->GetMeshNodeList();
|
||||
const auto& meshNodesWithBackstopData = editorClothComponent->GetMeshNodesWithBackstopData();
|
||||
|
||||
@@ -168,7 +168,7 @@ namespace UnitTest
|
||||
{
|
||||
{
|
||||
auto actor = AZStd::make_unique<ActorHelper>("actor_test");
|
||||
auto rootNodeIndex = actor->AddJoint(RootNodeName);
|
||||
actor->AddJoint(RootNodeName);
|
||||
auto meshNode1Index = actor->AddJoint(MeshNode1Name, AZ::Transform::CreateTranslation(AZ::Vector3(3.0f, -2.0f, 0.0f)), RootNodeName);
|
||||
auto otherNodeIndex = actor->AddJoint(OtherNodeName, AZ::Transform::CreateTranslation(AZ::Vector3(0.5f, 0.0f, 0.0f)), RootNodeName);
|
||||
auto meshNode2Index = actor->AddJoint(MeshNode2Name, AZ::Transform::CreateTranslation(AZ::Vector3(0.2f, 0.6f, 1.0f)), OtherNodeName);
|
||||
@@ -194,7 +194,7 @@ namespace UnitTest
|
||||
{
|
||||
{
|
||||
auto actor = AZStd::make_unique<ActorHelper>("actor_test");
|
||||
auto rootNodeIndex = actor->AddJoint(RootNodeName);
|
||||
actor->AddJoint(RootNodeName);
|
||||
auto meshNode1Index = actor->AddJoint(MeshNode1Name, AZ::Transform::CreateTranslation(AZ::Vector3(3.0f, -2.0f, 0.0f)), RootNodeName);
|
||||
auto otherNodeIndex = actor->AddJoint(OtherNodeName, AZ::Transform::CreateTranslation(AZ::Vector3(0.5f, 0.0f, 0.0f)), RootNodeName);
|
||||
auto meshNode2Index = actor->AddJoint(MeshNode2Name, AZ::Transform::CreateTranslation(AZ::Vector3(0.2f, 0.6f, 1.0f)), OtherNodeName);
|
||||
|
||||
Reference in New Issue
Block a user