Fixed cloth simulation generating incorrect normals

Fixed cloth simulation generating incorrect normals.
Also added option in Cloth Component to update normals of static particles (disabled by default).
User will want to keep the option disabled when continuity of the normals is important, like in characters, but for environmental cloth the mesh could look better when the normals of static particles are updated too.

Enable 'Update normals of static particles' option on blind slices of  Nvcloth gem

Fix unit tests
This commit is contained in:
Aaron Ruiz Mora
2021-05-17 09:53:14 +01:00
committed by GitHub
parent 8ed8c26864
commit 0b551a0c21
13 changed files with 77 additions and 49 deletions
@@ -36,6 +36,12 @@ namespace UnitTest
AZ::Vector3(1.0f, 0.0f, 0.0f),
AZ::Vector3(0.0f, 1.0f, 0.0f)
}};
const AZStd::vector<NvCloth::SimParticleFormat> MeshParticles = {{
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[0], 1.0f),
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[1], 1.0f),
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[2], 1.0f),
}};
const AZStd::vector<NvCloth::SimIndexType> MeshIndices = {{
0, 1, 2
@@ -98,7 +104,7 @@ namespace UnitTest
{
AZ::EntityId entityId;
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(entityId, {}, 0, 0, {});
NvCloth::ActorClothSkinning::Create(entityId, {}, {}, 0, {});
EXPECT_TRUE(actorClothSkinning.get() == nullptr);
}
@@ -107,7 +113,7 @@ namespace UnitTest
{
AZ::EntityId entityId;
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(entityId, MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices);
NvCloth::ActorClothSkinning::Create(entityId, MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices);
EXPECT_TRUE(actorClothSkinning.get() == nullptr);
}
@@ -122,7 +128,7 @@ namespace UnitTest
}
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), {}, 0, 0, {});
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), {}, {}, 0, {});
EXPECT_TRUE(actorClothSkinning.get() == nullptr);
}
@@ -139,7 +145,7 @@ namespace UnitTest
}
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices);
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices);
EXPECT_TRUE(actorClothSkinning.get() == nullptr);
}
@@ -156,7 +162,7 @@ namespace UnitTest
}
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices);
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices);
EXPECT_TRUE(actorClothSkinning.get() != nullptr);
}
@@ -184,20 +190,15 @@ namespace UnitTest
}
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices);
NvCloth::ActorClothSkinning::Create(actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices);
ASSERT_TRUE(actorClothSkinning.get() != nullptr);
const AZStd::vector<NvCloth::SimParticleFormat> clothParticles = {{
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[0], 1.0f),
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[1], 1.0f),
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[2], 1.0f),
}};
AZStd::vector<NvCloth::SimParticleFormat> skinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
AZStd::vector<NvCloth::SimParticleFormat> skinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
actorClothSkinning->UpdateSkinning();
actorClothSkinning->ApplySkinning(clothParticles, skinnedClothParticles);
actorClothSkinning->ApplySkinning(MeshParticles, skinnedClothParticles);
EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothParticles));
EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), MeshParticles));
// Update actor instance's joints transforms
const AZ::Transform newMeshNodeTransform = AZ::Transform::CreateRotationY(AZ::DegToRad(180.0f));
@@ -205,10 +206,10 @@ namespace UnitTest
currentPose->SetLocalSpaceTransform(0, newMeshNodeTransform);
actorComponent->GetActorInstance()->UpdateSkinningMatrices();
AZStd::vector<NvCloth::SimParticleFormat> newSkinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
AZStd::vector<NvCloth::SimParticleFormat> newSkinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
actorClothSkinning->UpdateSkinning();
actorClothSkinning->ApplySkinning(clothParticles, newSkinnedClothParticles);
actorClothSkinning->ApplySkinning(MeshParticles, newSkinnedClothParticles);
const AZ::Transform diffTransform = AZ::Transform::CreateRotationY(AZ::DegToRad(90.0f));
const AZStd::vector<NvCloth::SimParticleFormat> clothParticlesResult = {{
@@ -245,20 +246,15 @@ namespace UnitTest
}
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices);
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices);
ASSERT_TRUE(actorClothSkinning.get() != nullptr);
const AZStd::vector<NvCloth::SimParticleFormat> clothParticles = {{
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[0], 1.0f),
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[1], 1.0f),
NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[2], 1.0f),
}};
AZStd::vector<NvCloth::SimParticleFormat> skinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
AZStd::vector<NvCloth::SimParticleFormat> skinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
actorClothSkinning->UpdateSkinning();
actorClothSkinning->ApplySkinning(clothParticles, skinnedClothParticles);
actorClothSkinning->ApplySkinning(MeshParticles, skinnedClothParticles);
EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothParticles));
EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), MeshParticles));
// Update actor instance's joints transforms
const AZ::Transform newJointRootTransform = AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateRotationZ(AZ::DegToRad(-32.0f)), AZ::Vector3(2.5f, -6.0f, 0.2f));
@@ -268,10 +264,10 @@ namespace UnitTest
currentPose->SetLocalSpaceTransform(1, newJointChildTransform);
m_actorComponent->GetActorInstance()->UpdateSkinningMatrices();
AZStd::vector<NvCloth::SimParticleFormat> newSkinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
AZStd::vector<NvCloth::SimParticleFormat> newSkinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f));
actorClothSkinning->UpdateSkinning();
actorClothSkinning->ApplySkinning(clothParticles, newSkinnedClothParticles);
actorClothSkinning->ApplySkinning(MeshParticles, newSkinnedClothParticles);
const AZStd::vector<NvCloth::SimParticleFormat> clothParticlesResult = {{
NvCloth::SimParticleFormat(-48.4177f, -31.9446f, 45.2279f, 1.0f),
@@ -294,7 +290,7 @@ namespace UnitTest
}
AZStd::unique_ptr<NvCloth::ActorClothSkinning> actorClothSkinning =
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices);
NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices);
ASSERT_TRUE(actorClothSkinning.get() != nullptr);
EXPECT_FALSE(actorClothSkinning->IsActorVisible());