Terrain/sphrose/layer spawner (#3980)

* #3326 Get layer priorities to work.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Refresh terrain when layer settings change

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Removed dependency notification handling: it isn't needed due to deactivate/activate cycle caused by editor redrawing.
Moved layer registering to ordered map sorted by priority.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Remove unused code, add extra sort condition.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Fix copy/paste error.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Change erase method.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Review suggestions.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Fix bus disconnect order, change GetUseGroundPlane to return bool.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Create unit tests for Terrain Spawning component #3224

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Remove unintended commit.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* Remove blank line.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>

* PR changes.

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>
This commit is contained in:
sphrose
2021-09-08 16:55:22 +01:00
committed by GitHub
parent 817f8ce4c1
commit cc7cc9b7a8
8 changed files with 451 additions and 43 deletions
@@ -17,6 +17,33 @@
using namespace Terrain;
bool TerrainLayerPriorityComparator::operator()(const AZ::EntityId& layer1id, const AZ::EntityId& layer2id) const
{
// Comparator for insertion/keylookup.
// Sorts into layer/priority order, highest priority first.
AZ::u32 priority1, layer1;
Terrain::TerrainSpawnerRequestBus::Event(layer1id, &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer1, priority1);
AZ::u32 priority2, layer2;
Terrain::TerrainSpawnerRequestBus::Event(layer2id, &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer2, priority2);
if (layer1 < layer2)
{
return false;
}
else if (layer1 > layer2)
{
return true;
}
if (priority1 != priority2)
{
return priority1 > priority2;
}
return layer1id > layer2id;
}
TerrainSystem::TerrainSystem()
{
Terrain::TerrainSystemServiceRequestBus::Handler::BusConnect();
@@ -78,17 +105,14 @@ float TerrainSystem::GetHeightSynchronous(float x, float y) const
AZStd::shared_lock<AZStd::shared_mutex> lock(m_areaMutex);
if (!m_registeredAreas.empty())
for (auto& [areaId, areaBounds] : m_registeredAreas)
{
for (auto& [areaId, areaBounds] : m_registeredAreas)
inPosition.SetZ(areaBounds.GetMin().GetZ());
if (areaBounds.Contains(inPosition))
{
inPosition.SetZ(areaBounds.GetMin().GetZ());
if (areaBounds.Contains(inPosition))
{
Terrain::TerrainAreaHeightRequestBus::Event(
areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition,
Terrain::TerrainAreaHeightRequestBus::Events::Sampler::DEFAULT);
}
Terrain::TerrainAreaHeightRequestBus::Event(
areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition,
Terrain::TerrainAreaHeightRequestBus::Events::Sampler::DEFAULT);
}
}
@@ -305,26 +329,34 @@ void TerrainSystem::SystemDeactivate()
void TerrainSystem::RegisterArea(AZ::EntityId areaId)
{
{
AZStd::unique_lock<AZStd::shared_mutex> lock(m_areaMutex);
AZ::Aabb aabb = AZ::Aabb::CreateNull();
LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
m_registeredAreas[areaId] = aabb;
}
RefreshArea(areaId);
AZStd::unique_lock<AZStd::shared_mutex> lock(m_areaMutex);
AZ::Aabb aabb = AZ::Aabb::CreateNull();
LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
m_registeredAreas[areaId] = aabb;
m_dirtyRegion.AddAabb(aabb);
m_terrainHeightDirty = true;
}
void TerrainSystem::UnregisterArea(AZ::EntityId areaId)
{
{
AZStd::unique_lock<AZStd::shared_mutex> lock(m_areaMutex);
AZ::Aabb aabb = AZ::Aabb::CreateNull();
LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
m_registeredAreas.erase(areaId);
}
AZStd::unique_lock<AZStd::shared_mutex> lock(m_areaMutex);
RefreshArea(areaId);
// Remove the data for this entity from the registered areas.
// Erase_if is used as erase would use the comparator to lookup the entity id in the map.
// As the comparator will get the new layer/priority data for the entity, the id lookup will fail.
AZStd::erase_if(
m_registeredAreas,
[areaId, this](const auto& item)
{
auto const& [entityId, aabb] = item;
if (areaId == entityId)
{
m_dirtyRegion.AddAabb(aabb);
m_terrainHeightDirty = true;
return true;
}
return false;
});
}
void TerrainSystem::RefreshArea(AZ::EntityId areaId)
@@ -336,7 +368,6 @@ void TerrainSystem::RefreshArea(AZ::EntityId areaId)
AZ::Aabb oldAabb = (areaAabb != m_registeredAreas.end()) ? areaAabb->second : AZ::Aabb::CreateNull();
AZ::Aabb newAabb = AZ::Aabb::CreateNull();
LmbrCentral::ShapeComponentRequestsBus::EventResult(newAabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
m_registeredAreas[areaId] = newAabb;
AZ::Aabb expandedAabb = oldAabb;
@@ -400,31 +431,37 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
const uint32_t pixelDataSize = width * height * sizeof(float);
memset(pixels.data(), 0, pixelDataSize);
for (auto& [areaId, areaBounds] : m_registeredAreas)
for (uint32_t y = 0; y < height; y++)
{
for (uint32_t y = 0; y < height; y++)
for (uint32_t x = 0; x < width; x++)
{
for (uint32_t x = 0; x < width; x++)
// Find the first terrain layer that covers this position. This will be the highest priority, so others can be ignored.
for (auto& [areaId, areaBounds] : m_registeredAreas)
{
AZ::Vector3 inPosition(
(x * m_currentSettings.m_heightQueryResolution.GetX()) + m_currentSettings.m_worldBounds.GetMin().GetX(),
(y * m_currentSettings.m_heightQueryResolution.GetY()) + m_currentSettings.m_worldBounds.GetMin().GetY(),
areaBounds.GetMin().GetZ());
if (areaBounds.Contains(inPosition))
if (!areaBounds.Contains(inPosition))
{
AZ::Vector3 outPosition;
const Terrain::TerrainAreaHeightRequests::Sampler sampleFilter =
Terrain::TerrainAreaHeightRequests::Sampler::DEFAULT;
Terrain::TerrainAreaHeightRequestBus::Event(
areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, sampleFilter);
pixels[(y * width) + x] = (outPosition.GetZ() - m_currentSettings.m_worldBounds.GetMin().GetZ()) /
m_currentSettings.m_worldBounds.GetExtents().GetZ();
continue;
}
AZ::Vector3 outPosition;
const Terrain::TerrainAreaHeightRequests::Sampler sampleFilter = Terrain::TerrainAreaHeightRequests::Sampler::DEFAULT;
Terrain::TerrainAreaHeightRequestBus::Event(
areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, sampleFilter);
pixels[(y * width) + x] = (outPosition.GetZ() - m_currentSettings.m_worldBounds.GetMin().GetZ()) /
m_currentSettings.m_worldBounds.GetExtents().GetZ();
break;
}
}
}
const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get();
auto terrainFeatureProcessor = scene->GetFeatureProcessor<TerrainFeatureProcessor>();