LYN-7637 Allow Terrain Physics Collider to assign a default physics material

Signed-off-by: Sergey Pereslavtsev <pereslav@amazon.com>
This commit is contained in:
Sergey Pereslavtsev
2022-01-26 19:15:34 +00:00
parent 7b3631444d
commit 4c01c5b67f
3 changed files with 100 additions and 5 deletions
@@ -70,8 +70,9 @@ namespace Terrain
if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<TerrainPhysicsColliderConfig, AZ::ComponentConfig>()
->Version(2)->Field(
"Mappings", &TerrainPhysicsColliderConfig::m_surfaceMaterialMappings)
->Version(3)
->Field("DefaultMaterial", &TerrainPhysicsColliderConfig::m_defaultMaterialSelection)
->Field("Mappings", &TerrainPhysicsColliderConfig::m_surfaceMaterialMappings)
;
if (auto edit = serialize->GetEditContext())
@@ -82,6 +83,8 @@ namespace Terrain
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainPhysicsColliderConfig::m_defaultMaterialSelection,
"Default Surface Physics Material", "Select a material to be used by maps surfaces by default")
->DataElement(
AZ::Edit::UIHandlers::Default, &TerrainPhysicsColliderConfig::m_surfaceMaterialMappings,
"Surface to Material Mappings", "Maps surfaces to physics materials")
@@ -319,7 +322,7 @@ namespace Terrain
}
// If this surface isn't mapped, use the default material.
return Physics::MaterialId();
return m_configuration.m_defaultMaterialSelection.GetMaterialId();
}
void TerrainPhysicsColliderComponent::GenerateHeightsAndMaterialsInBounds(
@@ -417,7 +420,7 @@ namespace Terrain
AZStd::vector<Physics::MaterialId> materialList;
// Ensure the list contains the default material as the first entry.
materialList.emplace_back(Physics::MaterialId());
materialList.emplace_back(m_configuration.m_defaultMaterialSelection.GetMaterialId());
for (auto& mapping : m_configuration.m_surfaceMaterialMappings)
{
@@ -48,7 +48,7 @@ namespace Terrain
AZ_CLASS_ALLOCATOR(TerrainPhysicsColliderConfig, AZ::SystemAllocator, 0);
AZ_RTTI(TerrainPhysicsColliderConfig, "{E9EADB8F-C3A5-4B9C-A62D-2DBC86B4CE59}", AZ::ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
Physics::MaterialSelection m_defaultMaterialSelection;
AZStd::vector<TerrainPhysicsSurfaceMaterialMapping> m_surfaceMaterialMappings;
};
@@ -502,3 +502,95 @@ TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderGetHeightsAndM
m_entity.reset();
}
TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderDefaultMaterialAssignedWhenTagHasNoMapping)
{
CreateEntity();
m_boxComponent = m_entity->CreateComponent<UnitTest::MockAxisAlignedBoxShapeComponent>();
m_app.RegisterComponentDescriptor(m_boxComponent->CreateDescriptor());
// Create two SurfaceTag/Material mappings and add them to the collider.
Terrain::TerrainPhysicsColliderConfig config;
const Physics::MaterialId defaultSurfaceMaterial = Physics::MaterialId::Create();
const Physics::MaterialId mat1 = Physics::MaterialId::Create();
const SurfaceData::SurfaceTag tag1 = SurfaceData::SurfaceTag("tag1");
const SurfaceData::SurfaceTag tag2 = SurfaceData::SurfaceTag("tag2");
Terrain::TerrainPhysicsSurfaceMaterialMapping mapping1;
mapping1.m_materialId = mat1;
mapping1.m_surfaceTag = tag1;
config.m_surfaceMaterialMappings.emplace_back(mapping1);
config.m_defaultMaterialSelection.SetMaterialId(defaultSurfaceMaterial);
// Intentionally don't set the mapping for "tag2". It's expected the default material will substitute.
m_colliderComponent = m_entity->CreateComponent<Terrain::TerrainPhysicsColliderComponent>(config);
m_app.RegisterComponentDescriptor(m_colliderComponent->CreateDescriptor());
m_entity->Activate();
// Validate material list is generated with the default material
{
AZStd::vector<Physics::MaterialId> materialList;
Physics::HeightfieldProviderRequestsBus::EventResult(
materialList, m_entity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList);
// The materialList should be 2 items long: the default material and mat1.
EXPECT_EQ(materialList.size(), 2);
EXPECT_EQ(materialList[0], defaultSurfaceMaterial);
EXPECT_EQ(materialList[1], mat1);
}
const AZ::Vector3 boundsMin = AZ::Vector3(0.0f);
const AZ::Vector3 boundsMax = AZ::Vector3(256.0f, 256.0f, 32768.0f);
NiceMock<UnitTest::MockShapeComponentRequests> boxShape(m_entity->GetId());
const AZ::Aabb bounds = AZ::Aabb::CreateFromMinMax(boundsMin, boundsMax);
ON_CALL(boxShape, GetEncompassingAabb).WillByDefault(Return(bounds));
const float mockHeight = 32768.0f;
AZ::Vector2 mockHeightResolution = AZ::Vector2(1.0f);
AzFramework::SurfaceData::SurfaceTagWeight return1;
return1.m_surfaceType = tag1;
return1.m_weight = 1.0f;
AzFramework::SurfaceData::SurfaceTagWeight return2;
return2.m_surfaceType = tag2;
return2.m_weight = 1.0f;
AzFramework::SurfaceData::SurfaceTagWeightList surfaceTags = { return1, return2 };
NiceMock<UnitTest::MockTerrainDataRequests> terrainListener;
ON_CALL(terrainListener, GetTerrainHeightQueryResolution).WillByDefault(Return(mockHeightResolution));
ON_CALL(terrainListener, ProcessSurfacePointsFromRegion).WillByDefault(
[this, mockHeight, &surfaceTags](const AZ::Aabb& inRegion, const AZ::Vector2& stepSize,
AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback,
[[maybe_unused]] AzFramework::Terrain::TerrainDataRequests::Sampler sampleFilter)
{
ProcessRegionLoop(inRegion, stepSize, perPositionCallback, &surfaceTags, mockHeight);
}
);
// Validate material indices
{
AZStd::vector<Physics::HeightMaterialPoint> heightsAndMaterials;
Physics::HeightfieldProviderRequestsBus::EventResult(
heightsAndMaterials, m_entity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials);
// We set the bounds to 256, so check that the correct number of entries are present.
EXPECT_EQ(heightsAndMaterials.size(), 256 * 256);
// Check an entry from the first half of the returned list.
EXPECT_EQ(heightsAndMaterials[0].m_materialIndex, 1);
// Check an entry from the second half of the list.
// This should point to the default material (0) since we don't have a mapping for "tag2"
EXPECT_EQ(heightsAndMaterials[256 * 128].m_materialIndex, 0);
}
m_entity.reset();
}