First pass terrain cleanup (#3753)
* First pass cleanup of some terrain components. Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Adding basic culling to terrain sectors Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Adding default value for m_transform Signed-off-by: Ken Pruiksma <pruiksma@amazon.com>
This commit is contained in:
@@ -85,8 +85,10 @@ namespace Terrain
|
||||
|
||||
void TerrainWorldComponent::Activate()
|
||||
{
|
||||
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::SetWorldMin, m_configuration.m_worldMin);
|
||||
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::SetWorldMax, m_configuration.m_worldMax);
|
||||
TerrainSystemServiceRequestBus::Broadcast(
|
||||
&TerrainSystemServiceRequestBus::Events::SetWorldBounds,
|
||||
AZ::Aabb::CreateFromMinMax(m_configuration.m_worldMin, m_configuration.m_worldMax)
|
||||
);
|
||||
TerrainSystemServiceRequestBus::Broadcast(
|
||||
&TerrainSystemServiceRequestBus::Events::SetHeightQueryResolution, m_configuration.m_heightQueryResolution);
|
||||
|
||||
|
||||
@@ -92,20 +92,13 @@ namespace Terrain
|
||||
{
|
||||
m_wireframeBounds = AZ::Aabb::CreateNull();
|
||||
|
||||
TerrainSystemServiceRequestBus::Broadcast(
|
||||
&TerrainSystemServiceRequestBus::Events::SetDebugWireframe, m_configuration.m_drawWireframe);
|
||||
|
||||
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
|
||||
AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId());
|
||||
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
|
||||
|
||||
}
|
||||
|
||||
void TerrainWorldDebuggerComponent::Deactivate()
|
||||
{
|
||||
TerrainSystemServiceRequestBus::Broadcast(
|
||||
&TerrainSystemServiceRequestBus::Events::SetDebugWireframe, false);
|
||||
|
||||
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::BoundsRequestBus::Handler::BusDisconnect();
|
||||
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
|
||||
|
||||
@@ -10,12 +10,14 @@
|
||||
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Math/Frustum.h>
|
||||
|
||||
#include <Atom/Utils/Utils.h>
|
||||
|
||||
#include <Atom/RHI/DrawPacketBuilder.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
|
||||
@@ -34,6 +36,7 @@ namespace Terrain
|
||||
namespace
|
||||
{
|
||||
const uint32_t DEFAULT_UploadBufferSize = 512 * 1024; // 512k
|
||||
const char* TerrainFPName = "TerrainFeatureProcessor";
|
||||
}
|
||||
|
||||
namespace ShaderInputs
|
||||
@@ -59,7 +62,7 @@ namespace Terrain
|
||||
|
||||
void TerrainFeatureProcessor::Activate()
|
||||
{
|
||||
m_areaData.clear();
|
||||
m_areaData = {};
|
||||
|
||||
InitializeAtomStuff();
|
||||
EnableSceneNotification();
|
||||
@@ -69,43 +72,18 @@ namespace Terrain
|
||||
{
|
||||
m_rhiSystem = AZ::RHI::RHISystemInterface::Get();
|
||||
|
||||
m_rhiSystem->GetDrawListTagRegistry()->AcquireTag(AZ::Name("Terrain"));
|
||||
|
||||
{
|
||||
// Load the shader
|
||||
|
||||
const char* terrainShaderFilePath = "Shaders/Terrain/Terrain.azshader";
|
||||
|
||||
AZ::Data::AssetId shaderAssetId;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
shaderAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
|
||||
terrainShaderFilePath, azrtti_typeid<AZ::RPI::ShaderAsset>(), false);
|
||||
if (!shaderAssetId.IsValid())
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to get shader asset id with path %s", terrainShaderFilePath);
|
||||
return;
|
||||
}
|
||||
|
||||
auto shaderAsset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::ShaderAsset>(shaderAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
shaderAsset.BlockUntilLoadComplete();
|
||||
|
||||
if (!shaderAsset.IsReady())
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to get shader asset with path %s", terrainShaderFilePath);
|
||||
return;
|
||||
}
|
||||
|
||||
m_shader = AZ::RPI::Shader::FindOrCreate(shaderAsset);
|
||||
constexpr const char* TerrainShaderFilePath = "Shaders/Terrain/Terrain.azshader";
|
||||
m_shader = AZ::RPI::LoadShader(TerrainShaderFilePath);
|
||||
if (!m_shader)
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to find or create a shader instance from shader asset '%s'", terrainShaderFilePath);
|
||||
AZ_Error(TerrainFPName, false, "Failed to find or create a shader instance from shader asset '%s'", TerrainShaderFilePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the data layout
|
||||
|
||||
m_pipelineStateDescriptor = AZ::RHI::PipelineStateDescriptorForDraw{};
|
||||
|
||||
{
|
||||
AZ::RHI::InputStreamLayoutBuilder layoutBuilder;
|
||||
|
||||
@@ -124,41 +102,41 @@ namespace Terrain
|
||||
m_perObjectSrgAsset = m_shader->FindShaderResourceGroupLayout(AZ::Name{"ObjectSrg"});
|
||||
if (!m_perObjectSrgAsset)
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to get shader resource group asset");
|
||||
AZ_Error(TerrainFPName, false, "Failed to get shader resource group asset");
|
||||
return;
|
||||
}
|
||||
else if (!m_perObjectSrgAsset->IsFinalized())
|
||||
{
|
||||
AZ_Error("Terrain", false, "Shader resource group asset is not loaded");
|
||||
AZ_Error(TerrainFPName, false, "Shader resource group asset is not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
const AZ::RHI::ShaderResourceGroupLayout* shaderResourceGroupLayout = &(*m_perObjectSrgAsset);
|
||||
|
||||
m_heightmapImageIndex = shaderResourceGroupLayout->FindShaderInputImageIndex(AZ::Name(ShaderInputs::HeightmapImage));
|
||||
AZ_Error("Terrain", m_heightmapImageIndex.IsValid(), "Failed to find shader input image %s.", ShaderInputs::HeightmapImage);
|
||||
AZ_Error(TerrainFPName, m_heightmapImageIndex.IsValid(), "Failed to find shader input image %s.", ShaderInputs::HeightmapImage);
|
||||
|
||||
m_modelToWorldIndex = shaderResourceGroupLayout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::ModelToWorld));
|
||||
AZ_Error("Terrain", m_modelToWorldIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::ModelToWorld);
|
||||
AZ_Error(TerrainFPName, m_modelToWorldIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::ModelToWorld);
|
||||
|
||||
m_heightScaleIndex = shaderResourceGroupLayout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::HeightScale));
|
||||
AZ_Error("Terrain", m_heightScaleIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::HeightScale);
|
||||
AZ_Error(TerrainFPName, m_heightScaleIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::HeightScale);
|
||||
|
||||
m_uvMinIndex = shaderResourceGroupLayout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::UvMin));
|
||||
AZ_Error("Terrain", m_uvMinIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::UvMin);
|
||||
AZ_Error(TerrainFPName, m_uvMinIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::UvMin);
|
||||
|
||||
m_uvMaxIndex = shaderResourceGroupLayout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::UvMax));
|
||||
AZ_Error("Terrain", m_uvMaxIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::UvMax);
|
||||
AZ_Error(TerrainFPName, m_uvMaxIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::UvMax);
|
||||
|
||||
m_uvStepIndex = shaderResourceGroupLayout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::UvStep));
|
||||
AZ_Error("Terrain", m_uvStepIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::UvStep);
|
||||
AZ_Error(TerrainFPName, m_uvStepIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::UvStep);
|
||||
|
||||
// If this fails to run now, it's ok, we'll initialize it in OnRenderPipelineAdded later.
|
||||
bool success = GetParentScene()->ConfigurePipelineState(m_shader->GetDrawListTag(), m_pipelineStateDescriptor);
|
||||
if (success)
|
||||
{
|
||||
m_pipelineState = m_shader->AcquirePipelineState(m_pipelineStateDescriptor);
|
||||
AZ_Assert(m_pipelineState, "Failed to acquire default pipeline state for shader '%s'", terrainShaderFilePath);
|
||||
AZ_Assert(m_pipelineState, "Failed to acquire default pipeline state for shader '%s'", TerrainShaderFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +150,7 @@ namespace Terrain
|
||||
|
||||
if (resultCode != AZ::RHI::ResultCode::Success)
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to create host buffer pool from RPI");
|
||||
AZ_Error(TerrainFPName, false, "Failed to create host buffer pool from RPI");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,7 +158,7 @@ namespace Terrain
|
||||
|
||||
if (!InitializeRenderBuffers())
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to create Terrain render buffers!");
|
||||
AZ_Error(TerrainFPName, false, "Failed to create Terrain render buffers!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +188,7 @@ namespace Terrain
|
||||
DisableSceneNotification();
|
||||
|
||||
DestroyRenderBuffers();
|
||||
m_areaData.clear();
|
||||
m_areaData = {};
|
||||
|
||||
if (m_hostPool)
|
||||
{
|
||||
@@ -226,7 +204,6 @@ namespace Terrain
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::UpdateTerrainData(
|
||||
AZ::EntityId areaId,
|
||||
const AZ::Transform& transform,
|
||||
const AZ::Aabb& worldBounds,
|
||||
[[maybe_unused]] float sampleSpacing,
|
||||
@@ -234,37 +211,33 @@ namespace Terrain
|
||||
{
|
||||
if (!worldBounds.IsValid())
|
||||
{
|
||||
m_areaData.erase(areaId);
|
||||
return;
|
||||
}
|
||||
|
||||
TerrainAreaData areaData;
|
||||
|
||||
areaData.m_transform = transform;
|
||||
areaData.m_heightScale = worldBounds.GetZExtent();
|
||||
areaData.m_terrainBounds = worldBounds;
|
||||
areaData.m_heightmapImageHeight = height;
|
||||
areaData.m_heightmapImageWidth = width;
|
||||
m_areaData.m_transform = transform;
|
||||
m_areaData.m_heightScale = worldBounds.GetZExtent();
|
||||
m_areaData.m_terrainBounds = worldBounds;
|
||||
m_areaData.m_heightmapImageHeight = height;
|
||||
m_areaData.m_heightmapImageWidth = width;
|
||||
|
||||
// Create heightmap image data
|
||||
{
|
||||
areaData.m_propertiesDirty = true;
|
||||
m_areaData.m_propertiesDirty = true;
|
||||
|
||||
AZ::RHI::Size imageSize;
|
||||
imageSize.m_width = width;
|
||||
imageSize.m_height = height;
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::StreamingImagePool> streamingImagePool = AZ::RPI::ImageSystemInterface::Get()->GetSystemStreamingPool();
|
||||
areaData.m_heightmapImage = AZ::RPI::StreamingImage::CreateFromCpuData(*streamingImagePool,
|
||||
m_areaData.m_heightmapImage = AZ::RPI::StreamingImage::CreateFromCpuData(*streamingImagePool,
|
||||
AZ::RHI::ImageDimension::Image2D,
|
||||
imageSize,
|
||||
AZ::RHI::Format::R32_FLOAT,
|
||||
(uint8_t*)heightData.data(),
|
||||
heightData.size() * sizeof(float));
|
||||
AZ_Error("Terrain", areaData.m_heightmapImage, "Failed to initialize the heightmap image!");
|
||||
AZ_Error(TerrainFPName, m_areaData.m_heightmapImage, "Failed to initialize the heightmap image!");
|
||||
}
|
||||
|
||||
m_areaData.insert_or_assign(areaId, areaData);
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::ProcessSurfaces(const FeatureProcessor::RenderPacket& process)
|
||||
@@ -276,31 +249,30 @@ namespace Terrain
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_areaData.empty())
|
||||
if (!m_areaData.m_terrainBounds.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_drawPackets.clear();
|
||||
m_processSrgs.clear();
|
||||
|
||||
AZ::RHI::DrawPacketBuilder drawPacketBuilder;
|
||||
|
||||
uint32_t numIndices = static_cast<uint32_t>(m_gridIndices.size());
|
||||
|
||||
AZ::RHI::DrawIndexed drawIndexed;
|
||||
drawIndexed.m_indexCount = numIndices;
|
||||
drawIndexed.m_indexOffset = 0;
|
||||
drawIndexed.m_vertexOffset = 0;
|
||||
|
||||
for (auto& [areaId, areaData] : m_areaData)
|
||||
|
||||
if (m_areaData.m_propertiesDirty)
|
||||
{
|
||||
m_sectorData.clear();
|
||||
|
||||
AZ::RHI::DrawPacketBuilder drawPacketBuilder;
|
||||
|
||||
uint32_t numIndices = static_cast<uint32_t>(m_gridIndices.size());
|
||||
|
||||
AZ::RHI::DrawIndexed drawIndexed;
|
||||
drawIndexed.m_indexCount = numIndices;
|
||||
drawIndexed.m_indexOffset = 0;
|
||||
drawIndexed.m_vertexOffset = 0;
|
||||
|
||||
float xFirstPatchStart =
|
||||
areaData.m_terrainBounds.GetMin().GetX() - fmod(areaData.m_terrainBounds.GetMin().GetX(), m_gridMeters);
|
||||
float xLastPatchStart = areaData.m_terrainBounds.GetMax().GetX() - fmod(areaData.m_terrainBounds.GetMax().GetX(), m_gridMeters);
|
||||
m_areaData.m_terrainBounds.GetMin().GetX() - fmod(m_areaData.m_terrainBounds.GetMin().GetX(), m_gridMeters);
|
||||
float xLastPatchStart = m_areaData.m_terrainBounds.GetMax().GetX() - fmod(m_areaData.m_terrainBounds.GetMax().GetX(), m_gridMeters);
|
||||
float yFirstPatchStart =
|
||||
areaData.m_terrainBounds.GetMin().GetY() - fmod(areaData.m_terrainBounds.GetMin().GetY(), m_gridMeters);
|
||||
float yLastPatchStart = areaData.m_terrainBounds.GetMax().GetY() - fmod(areaData.m_terrainBounds.GetMax().GetY(), m_gridMeters);
|
||||
m_areaData.m_terrainBounds.GetMin().GetY() - fmod(m_areaData.m_terrainBounds.GetMin().GetY(), m_gridMeters);
|
||||
float yLastPatchStart = m_areaData.m_terrainBounds.GetMax().GetY() - fmod(m_areaData.m_terrainBounds.GetMax().GetY(), m_gridMeters);
|
||||
|
||||
for (float yPatch = yFirstPatchStart; yPatch <= yLastPatchStart; yPatch += m_gridMeters)
|
||||
{
|
||||
@@ -310,62 +282,70 @@ namespace Terrain
|
||||
drawPacketBuilder.SetDrawArguments(drawIndexed);
|
||||
drawPacketBuilder.SetIndexBufferView(m_indexBufferView);
|
||||
|
||||
auto m_resourceGroup = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), AZ::Name("ObjectSrg"));
|
||||
auto resourceGroup = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), AZ::Name("ObjectSrg"));
|
||||
//auto m_resourceGroup = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), AZ::Name("ObjectSrg"));
|
||||
if (!m_resourceGroup)
|
||||
if (!resourceGroup)
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to create shader resource group");
|
||||
AZ_Error(TerrainFPName, false, "Failed to create shader resource group");
|
||||
return;
|
||||
}
|
||||
|
||||
float uvMin[2] = { 0.0f, 0.0f };
|
||||
float uvMax[2] = { 1.0f, 1.0f };
|
||||
|
||||
uvMin[0] = (float)((xPatch - areaData.m_terrainBounds.GetMin().GetX()) / areaData.m_terrainBounds.GetXExtent());
|
||||
uvMin[1] = (float)((yPatch - areaData.m_terrainBounds.GetMin().GetY()) / areaData.m_terrainBounds.GetYExtent());
|
||||
uvMin[0] = (float)((xPatch - m_areaData.m_terrainBounds.GetMin().GetX()) / m_areaData.m_terrainBounds.GetXExtent());
|
||||
uvMin[1] = (float)((yPatch - m_areaData.m_terrainBounds.GetMin().GetY()) / m_areaData.m_terrainBounds.GetYExtent());
|
||||
|
||||
uvMax[0] =
|
||||
(float)(((xPatch + m_gridMeters) - areaData.m_terrainBounds.GetMin().GetX()) / areaData.m_terrainBounds.GetXExtent());
|
||||
(float)(((xPatch + m_gridMeters) - m_areaData.m_terrainBounds.GetMin().GetX()) / m_areaData.m_terrainBounds.GetXExtent());
|
||||
uvMax[1] =
|
||||
(float)(((yPatch + m_gridMeters) - areaData.m_terrainBounds.GetMin().GetY()) / areaData.m_terrainBounds.GetYExtent());
|
||||
(float)(((yPatch + m_gridMeters) - m_areaData.m_terrainBounds.GetMin().GetY()) / m_areaData.m_terrainBounds.GetYExtent());
|
||||
|
||||
float uvStep[2] =
|
||||
{
|
||||
1.0f / areaData.m_heightmapImageWidth, 1.0f / areaData.m_heightmapImageHeight,
|
||||
1.0f / m_areaData.m_heightmapImageWidth, 1.0f / m_areaData.m_heightmapImageHeight,
|
||||
};
|
||||
|
||||
AZ::Transform transform = areaData.m_transform;
|
||||
transform.SetTranslation(xPatch, yPatch, areaData.m_transform.GetTranslation().GetZ());
|
||||
AZ::Transform transform = m_areaData.m_transform;
|
||||
transform.SetTranslation(xPatch, yPatch, m_areaData.m_transform.GetTranslation().GetZ());
|
||||
|
||||
AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromTransform(transform);
|
||||
|
||||
m_resourceGroup->SetImage(m_heightmapImageIndex, areaData.m_heightmapImage);
|
||||
m_resourceGroup->SetConstant(m_modelToWorldIndex, matrix3x4);
|
||||
m_resourceGroup->SetConstant(m_heightScaleIndex, areaData.m_heightScale);
|
||||
m_resourceGroup->SetConstant(m_uvMinIndex, uvMin);
|
||||
m_resourceGroup->SetConstant(m_uvMaxIndex, uvMax);
|
||||
m_resourceGroup->SetConstant(m_uvStepIndex, uvStep);
|
||||
m_resourceGroup->Compile();
|
||||
m_processSrgs.push_back(m_resourceGroup);
|
||||
|
||||
if (m_resourceGroup != nullptr)
|
||||
{
|
||||
drawPacketBuilder.AddShaderResourceGroup(m_resourceGroup->GetRHIShaderResourceGroup());
|
||||
}
|
||||
resourceGroup->SetImage(m_heightmapImageIndex, m_areaData.m_heightmapImage);
|
||||
resourceGroup->SetConstant(m_modelToWorldIndex, matrix3x4);
|
||||
resourceGroup->SetConstant(m_heightScaleIndex, m_areaData.m_heightScale);
|
||||
resourceGroup->SetConstant(m_uvMinIndex, uvMin);
|
||||
resourceGroup->SetConstant(m_uvMaxIndex, uvMax);
|
||||
resourceGroup->SetConstant(m_uvStepIndex, uvStep);
|
||||
resourceGroup->Compile();
|
||||
drawPacketBuilder.AddShaderResourceGroup(resourceGroup->GetRHIShaderResourceGroup());
|
||||
|
||||
AZ::RHI::DrawPacketBuilder::DrawRequest drawRequest;
|
||||
drawRequest.m_listTag = m_drawListTag;
|
||||
drawRequest.m_pipelineState = m_pipelineState.get();
|
||||
drawRequest.m_streamBufferViews = m_vertexBufferViews;
|
||||
drawRequest.m_streamBufferViews = AZStd::array_view<AZ::RHI::StreamBufferView>(&m_vertexBufferView, 1);
|
||||
drawPacketBuilder.AddDrawItem(drawRequest);
|
||||
|
||||
const AZ::RHI::DrawPacket* drawPacket = drawPacketBuilder.End();
|
||||
m_drawPackets.emplace_back(drawPacket);
|
||||
|
||||
for (auto& view : process.m_views)
|
||||
{
|
||||
view->AddDrawPacket(drawPacket);
|
||||
}
|
||||
|
||||
m_sectorData.emplace_back(
|
||||
drawPacketBuilder.End(),
|
||||
AZ::Aabb::CreateFromMinMax(
|
||||
AZ::Vector3(xPatch, yPatch, m_areaData.m_terrainBounds.GetMin().GetZ()),
|
||||
AZ::Vector3(xPatch + m_gridMeters, yPatch + m_gridMeters, m_areaData.m_terrainBounds.GetMax().GetZ())
|
||||
),
|
||||
resourceGroup
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& view : process.m_views)
|
||||
{
|
||||
AZ::Frustum viewFrustum = AZ::Frustum::CreateFromMatrixColumnMajor(view->GetWorldToClipMatrix());
|
||||
for (auto& sectorData : m_sectorData)
|
||||
{
|
||||
if (viewFrustum.IntersectAabb(sectorData.m_aabb) != AZ::IntersectResult::Exterior)
|
||||
{
|
||||
view->AddDrawPacket(sectorData.m_drawPacket.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -413,9 +393,6 @@ namespace Terrain
|
||||
m_indexBuffer->SetName(AZ::Name("TerrainIndexBuffer"));
|
||||
m_vertexBuffer->SetName(AZ::Name("TerrainVertexBuffer"));
|
||||
|
||||
// We only need one vertex buffer view.
|
||||
m_vertexBufferViews.resize(1);
|
||||
|
||||
AZStd::vector<AZ::RHI::Ptr<AZ::RHI::Buffer>> buffers = { m_indexBuffer , m_vertexBuffer };
|
||||
|
||||
// Fill our buffers with the vertex/index data
|
||||
@@ -433,7 +410,7 @@ namespace Terrain
|
||||
|
||||
if (result != AZ::RHI::ResultCode::Success)
|
||||
{
|
||||
AZ_Error("Terrain", false, "Failed to create GPU buffers for Terrain");
|
||||
AZ_Error(TerrainFPName, false, "Failed to create GPU buffers for Terrain");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -462,10 +439,10 @@ namespace Terrain
|
||||
const uint64_t elementSize = m_gridVertices.size() * sizeof(Vertex);
|
||||
memcpy(mappedData, m_gridVertices.data(), elementSize);
|
||||
|
||||
m_vertexBufferViews[bufferIndex - 1] = AZ::RHI::StreamBufferView(
|
||||
m_vertexBufferView = AZ::RHI::StreamBufferView(
|
||||
*buffer, 0, static_cast<uint32_t>(elementSize), static_cast<uint32_t>(sizeof(Vertex)));
|
||||
|
||||
AZ::RHI::ValidateStreamBufferViews(m_pipelineStateDescriptor.m_inputStreamLayout, m_vertexBufferViews);
|
||||
AZ::RHI::ValidateStreamBufferViews(m_pipelineStateDescriptor.m_inputStreamLayout, { { m_vertexBufferView } });
|
||||
}
|
||||
|
||||
m_hostPool->UnmapBuffer(*buffer);
|
||||
@@ -479,9 +456,8 @@ namespace Terrain
|
||||
m_indexBuffer.reset();
|
||||
m_vertexBuffer.reset();
|
||||
|
||||
m_vertexBufferViews.clear();
|
||||
|
||||
m_processSrgs.clear();
|
||||
m_indexBufferView = {};
|
||||
m_vertexBufferView = {};
|
||||
|
||||
m_pipelineStateDescriptor = AZ::RHI::PipelineStateDescriptorForDraw{};
|
||||
m_pipelineState = nullptr;
|
||||
|
||||
@@ -47,16 +47,12 @@ namespace Terrain
|
||||
void Deactivate() override;
|
||||
void Render(const AZ::RPI::FeatureProcessor::RenderPacket& packet) override;
|
||||
|
||||
void UpdateTerrainData(AZ::EntityId areaId, const AZ::Transform& transform, const AZ::Aabb& worldBounds, float sampleSpacing,
|
||||
void UpdateTerrainData(const AZ::Transform& transform, const AZ::Aabb& worldBounds, float sampleSpacing,
|
||||
uint32_t width, uint32_t height, const AZStd::vector<float>& heightData);
|
||||
|
||||
void RemoveTerrainData(AZ::EntityId areaId)
|
||||
{
|
||||
m_areaData.erase(areaId);
|
||||
}
|
||||
void RemoveTerrainData()
|
||||
{
|
||||
m_areaData.clear();
|
||||
m_areaData = {};
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -122,13 +118,13 @@ namespace Terrain
|
||||
AZ::RHI::Ptr<AZ::RHI::Buffer> m_indexBuffer;
|
||||
AZ::RHI::Ptr<AZ::RHI::Buffer> m_vertexBuffer;
|
||||
AZ::RHI::IndexBufferView m_indexBufferView;
|
||||
AZStd::fixed_vector<AZ::RHI::StreamBufferView, AZ::RHI::Limits::Pipeline::StreamCountMax> m_vertexBufferViews;
|
||||
AZ::RHI::StreamBufferView m_vertexBufferView;
|
||||
|
||||
// Per-area data
|
||||
struct TerrainAreaData
|
||||
{
|
||||
AZ::Transform m_transform;
|
||||
AZ::Aabb m_terrainBounds;
|
||||
AZ::Transform m_transform{ AZ::Transform::CreateIdentity() };
|
||||
AZ::Aabb m_terrainBounds{ AZ::Aabb::CreateNull() };
|
||||
float m_heightScale;
|
||||
AZ::Data::Instance<AZ::RPI::StreamingImage> m_heightmapImage;
|
||||
uint32_t m_heightmapImageWidth;
|
||||
@@ -136,10 +132,21 @@ namespace Terrain
|
||||
bool m_propertiesDirty{ true };
|
||||
};
|
||||
|
||||
AZStd::unordered_map<AZ::EntityId, TerrainAreaData> m_areaData;
|
||||
TerrainAreaData m_areaData;
|
||||
|
||||
// These could either be per-area or system-level
|
||||
AZStd::vector<AZStd::unique_ptr<const AZ::RHI::DrawPacket>> m_drawPackets;
|
||||
AZStd::vector<AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>> m_processSrgs;
|
||||
struct SectorData
|
||||
{
|
||||
AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> m_srg;
|
||||
AZ::Aabb m_aabb;
|
||||
AZStd::unique_ptr<const AZ::RHI::DrawPacket> m_drawPacket;
|
||||
|
||||
SectorData(const AZ::RHI::DrawPacket* drawPacket, AZ::Aabb aabb, AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> srg)
|
||||
: m_srg(srg)
|
||||
, m_aabb(aabb)
|
||||
, m_drawPacket(drawPacket)
|
||||
{}
|
||||
};
|
||||
|
||||
AZStd::vector<SectorData> m_sectorData;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -49,15 +49,9 @@ void TerrainSystem::Deactivate()
|
||||
m_terrainSettingsDirty = true;
|
||||
}
|
||||
|
||||
void TerrainSystem::SetWorldMin(AZ::Vector3 worldOrigin)
|
||||
{
|
||||
m_requestedSettings.m_worldBounds.SetMin(worldOrigin);
|
||||
m_terrainSettingsDirty = true;
|
||||
}
|
||||
|
||||
void TerrainSystem::SetWorldMax(AZ::Vector3 worldBounds)
|
||||
{
|
||||
m_requestedSettings.m_worldBounds.SetMax(worldBounds);
|
||||
void TerrainSystem::SetWorldBounds(const AZ::Aabb& worldBounds)
|
||||
{
|
||||
m_requestedSettings.m_worldBounds = worldBounds;
|
||||
m_terrainSettingsDirty = true;
|
||||
}
|
||||
|
||||
@@ -67,13 +61,6 @@ void TerrainSystem::SetHeightQueryResolution(AZ::Vector2 queryResolution)
|
||||
m_terrainSettingsDirty = true;
|
||||
}
|
||||
|
||||
void TerrainSystem::SetDebugWireframe(bool wireframeEnabled)
|
||||
{
|
||||
m_requestedSettings.m_debugWireframeEnabled = wireframeEnabled;
|
||||
m_terrainSettingsDirty = true;
|
||||
}
|
||||
|
||||
|
||||
AZ::Aabb TerrainSystem::GetTerrainAabb() const
|
||||
{
|
||||
return m_currentSettings.m_worldBounds;
|
||||
@@ -378,13 +365,6 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
|
||||
terrainSettingsChanged = true;
|
||||
}
|
||||
|
||||
if (m_requestedSettings.m_debugWireframeEnabled != m_currentSettings.m_debugWireframeEnabled)
|
||||
{
|
||||
m_dirtyRegion = AZ::Aabb::CreateNull();
|
||||
m_terrainHeightDirty = true;
|
||||
terrainSettingsChanged = true;
|
||||
}
|
||||
|
||||
if (m_requestedSettings.m_heightQueryResolution != m_currentSettings.m_heightQueryResolution)
|
||||
{
|
||||
m_dirtyRegion = AZ::Aabb::CreateNull();
|
||||
@@ -409,7 +389,6 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
|
||||
{
|
||||
AZStd::shared_lock<AZStd::shared_mutex> lock(m_areaMutex);
|
||||
|
||||
AZ::EntityId entityId(0);
|
||||
AZ::Transform transform = AZ::Transform::CreateTranslation(m_currentSettings.m_worldBounds.GetCenter());
|
||||
|
||||
uint32_t width = aznumeric_cast<uint32_t>(
|
||||
@@ -417,7 +396,7 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
|
||||
uint32_t height = aznumeric_cast<uint32_t>(
|
||||
(float)m_currentSettings.m_worldBounds.GetYExtent() / m_currentSettings.m_heightQueryResolution.GetY());
|
||||
AZStd::vector<float> pixels;
|
||||
pixels.resize(width * height);
|
||||
pixels.resize_no_construct(width * height);
|
||||
const uint32_t pixelDataSize = width * height * sizeof(float);
|
||||
memset(pixels.data(), 0, pixelDataSize);
|
||||
|
||||
@@ -454,8 +433,7 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
|
||||
if (terrainFeatureProcessor)
|
||||
{
|
||||
terrainFeatureProcessor->UpdateTerrainData(
|
||||
entityId, transform, m_currentSettings.m_worldBounds, m_currentSettings.m_heightQueryResolution.GetX(), width, height,
|
||||
pixels);
|
||||
transform, m_currentSettings.m_worldBounds, m_currentSettings.m_heightQueryResolution.GetX(), width, height, pixels);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,9 @@ namespace Terrain
|
||||
|
||||
///////////////////////////////////////////
|
||||
// TerrainSystemServiceRequestBus::Handler Impl
|
||||
|
||||
void SetWorldMin(AZ::Vector3 worldOrigin) override;
|
||||
void SetWorldMax(AZ::Vector3 worldBounds) override;
|
||||
|
||||
void SetWorldBounds(const AZ::Aabb& worldBounds) override;
|
||||
void SetHeightQueryResolution(AZ::Vector2 queryResolution) override;
|
||||
void SetDebugWireframe(bool wireframeEnabled) override;
|
||||
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
@@ -103,7 +101,6 @@ namespace Terrain
|
||||
{
|
||||
AZ::Aabb m_worldBounds;
|
||||
AZ::Vector2 m_heightQueryResolution{ 1.0f };
|
||||
bool m_debugWireframeEnabled{ false };
|
||||
bool m_systemActive{ false };
|
||||
};
|
||||
|
||||
|
||||
@@ -39,10 +39,8 @@ namespace Terrain
|
||||
virtual void Activate() = 0;
|
||||
virtual void Deactivate() = 0;
|
||||
|
||||
virtual void SetWorldMin(AZ::Vector3 worldOrigin) = 0;
|
||||
virtual void SetWorldMax(AZ::Vector3 worldBounds) = 0;
|
||||
virtual void SetWorldBounds(const AZ::Aabb& worldBounds) = 0;
|
||||
virtual void SetHeightQueryResolution(AZ::Vector2 queryResolution) = 0;
|
||||
virtual void SetDebugWireframe(bool wireframeEnabled) = 0;
|
||||
|
||||
// register an area to override terrain
|
||||
virtual void RegisterArea(AZ::EntityId areaId) = 0;
|
||||
@@ -111,8 +109,6 @@ namespace Terrain
|
||||
|
||||
virtual void GetHeight(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, Sampler sampleFilter = Sampler::DEFAULT) = 0;
|
||||
virtual void GetNormal(const AZ::Vector3& inPosition, AZ::Vector3& outNormal, Sampler sampleFilter = Sampler::DEFAULT) = 0;
|
||||
//virtual void GetSurfaceWeights(const AZ::Vector3& inPosition, SurfaceTagWeightMap& outSurfaceWeights, Sampler sampleFilter = DEFAULT) = 0;
|
||||
//virtual void GetSurfacePoint(const AZ::Vector3& inPosition, SurfacePoint& outSurfacePoint, SurfacePointDataMask dataMask = DEFAULT, Sampler sampleFilter = DEFAULT) = 0;
|
||||
};
|
||||
|
||||
using TerrainAreaHeightRequestBus = AZ::EBus<TerrainAreaHeightRequests>;
|
||||
|
||||
Reference in New Issue
Block a user