Skip to content

Commit

Permalink
Traktor: Refactored UndergrowthComponent, able to draw all undergrowt…
Browse files Browse the repository at this point in the history
…h in one draw call. Still "replanting" need to be moved to compute.
  • Loading branch information
apistol78 committed Feb 19, 2024
1 parent f88e7c8 commit 6f841e1
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 157 deletions.
168 changes: 77 additions & 91 deletions code/Terrain/UndergrowthComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* TRAKTOR
* Copyright (c) 2022 Anders Pistol.
* Copyright (c) 2022-2024 Anders Pistol.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down Expand Up @@ -43,14 +43,28 @@ struct Vertex
};
#pragma pack()

#pragma pack(1)
struct PlantData
{
float positionX;
float positionZ;
float plant;
float dummy1;
float scale;
float random;
float dummy2;
float dummy3;
};
#pragma pack()

const render::Handle s_handleTerrain_Normals(L"Terrain_Normals");
const render::Handle s_handleTerrain_Heightfield(L"Terrain_Heightfield");
const render::Handle s_handleTerrain_SurfaceAlbedo(L"Terrain_SurfaceAlbedo");
const render::Handle s_handleTerrain_WorldExtent(L"Terrain_WorldExtent");
const render::Handle s_handleUndergrowth_Eye(L"Undergrowth_Eye");
const render::Handle s_handleUndergrowth_MaxDistance(L"Undergrowth_MaxDistance");
const render::Handle s_handleUndergrowth_Instances1(L"Undergrowth_Instances1");
const render::Handle s_handleUndergrowth_Instances2(L"Undergrowth_Instances2");
const render::Handle s_handleUndergrowth_Plants(L"Undergrowth_Plants");
const render::Handle s_handleUndergrowth_Order(L"Undergrowth_Order");

Vertex packVertex(const Vector4& position, float u, float v)
{
Expand Down Expand Up @@ -133,11 +147,14 @@ bool UndergrowthComponent::create(
*index++ = 0;

m_indexBuffer->unlock();

m_renderSystem = renderSystem;
return true;
}

void UndergrowthComponent::destroy()
{
m_renderSystem = nullptr;
}

void UndergrowthComponent::setOwner(world::Entity* owner)
Expand Down Expand Up @@ -170,6 +187,9 @@ void UndergrowthComponent::build(
if (!terrainComponent)
return;

if (!m_plantsCount)
return;

const auto& terrain = terrainComponent->getTerrain();

// Update clusters at first pass from eye pow.
Expand All @@ -181,11 +201,10 @@ void UndergrowthComponent::build(

// Get plant state for current view.
ViewState& vs = m_viewState[worldRenderView.getIndex()];
if (vs.plants.size() != m_plantsCount * 2)
if (vs.plantBuffer == nullptr || vs.plantBuffer->getBufferSize() / sizeof(PlantData) != m_plantsCount)
{
vs.plants.resize(m_plantsCount * 2, Vector4::zero());
vs.distances.resize(m_clusters.size(), 0.0f);
vs.pvs.assign((uint32_t)m_clusters.size(), false);
vs.plantBuffer = m_renderSystem->createBuffer(render::BufferUsage::BuStructured, m_plantsCount * sizeof(PlantData), true);
vs.orderBuffer = m_renderSystem->createBuffer(render::BufferUsage::BuStructured, m_plantsCount * sizeof(int32_t), true);
updateClusters = true;
}

Expand All @@ -194,19 +213,19 @@ void UndergrowthComponent::build(
Frustum viewFrustum = worldRenderView.getViewFrustum();
viewFrustum.setFarZ(Scalar(m_layerData.m_spreadDistance + m_clusterSize));

vs.drawInstanceCount = 0;

PlantData* plantData = (PlantData*)vs.plantBuffer->lock();
int32_t* orderPtr = (int32_t*)vs.orderBuffer->lock();

// Only perform "replanting" half of clusters each frame.
const Scalar clusterSize(m_clusterSize);
for (uint32_t i = vs.count % 2; i < m_clusters.size(); i += 2)
//for (uint32_t i = vs.count % 2; i < m_clusters.size(); i += 2)
for (uint32_t i = 0; i < m_clusters.size(); ++i)
{
const Cluster& cluster = m_clusters[i];

vs.distances[i] = (cluster.center - eye).length();

const bool visible = vs.pvs[i];
vs.pvs.set(i, viewFrustum.inside(view * cluster.center, clusterSize) != Frustum::Result::Outside);
if (!vs.pvs[i])
continue;
if (vs.pvs[i] && visible)
if (viewFrustum.inside(view * cluster.center, clusterSize) == Frustum::Result::Outside)
continue;

RandomGeometry random(int32_t(cluster.center.x() * 919.0f + cluster.center.z() * 463.0f));
Expand All @@ -220,22 +239,21 @@ void UndergrowthComponent::build(
const float px = cluster.center.x() + dx;
const float pz = cluster.center.z() + dz;

vs.plants[j * 2 + 0] = Vector4(
px,
pz,
float(cluster.plant),
0.0f
);
vs.plants[j * 2 + 1] = Vector4(
cluster.plantScale * (random.nextFloat() * 0.5f + 0.5f),
random.nextFloat(),
0.0f,
0.0f
);
auto& pd = plantData[j];
pd.positionX = px;
pd.positionZ = pz;
pd.plant = float(cluster.plant);
pd.scale = cluster.plantScale * (random.nextFloat() * 0.5f + 0.5f);
pd.random = random.nextFloat();

*orderPtr++ = j;
}

vs.drawInstanceCount += cluster.to - cluster.from;
}

vs.count++;
vs.plantBuffer->unlock();
vs.orderBuffer->unlock();
}

auto sp = worldRenderPass.getProgram(m_shader);
Expand All @@ -244,69 +262,37 @@ void UndergrowthComponent::build(

render::RenderContext* renderContext = context.getRenderContext();

render::ProgramParameters* extraParameters = renderContext->alloc< render::ProgramParameters >();
extraParameters->beginParameters(renderContext);
extraParameters->setTextureParameter(s_handleTerrain_Normals, terrain->getNormalMap());
extraParameters->setTextureParameter(s_handleTerrain_Heightfield, terrain->getHeightMap());
extraParameters->setTextureParameter(s_handleTerrain_SurfaceAlbedo, terrainComponent->getSurfaceCache(worldRenderView.getIndex())->getBaseTexture());
extraParameters->setVectorParameter(s_handleTerrain_WorldExtent, terrain->getHeightfield()->getWorldExtent());
extraParameters->setVectorParameter(s_handleUndergrowth_Eye, eye);
extraParameters->setFloatParameter(s_handleUndergrowth_MaxDistance, m_layerData.m_spreadDistance + m_clusterSize);
extraParameters->endParameters(renderContext);

Vector4 instanceData1[c_maxInstanceCount];
Vector4 instanceData2[c_maxInstanceCount];

for (uint32_t i = 0; i < m_clusters.size(); ++i)
{
if (!vs.pvs[i])
continue;

const Cluster& cluster = m_clusters[i];

const int32_t count = cluster.to - cluster.from;
for (int32_t j = 0; j < count; )
{
const int32_t batch = std::min(count - j, c_maxInstanceCount);

for (int32_t k = 0; k < batch; ++k, ++j)
{
instanceData1[k] = vs.plants[(j + cluster.from) * 2 + 0];
instanceData2[k] = vs.plants[(j + cluster.from) * 2 + 1];
}

auto renderBlock = renderContext->allocNamed< render::IndexedInstancingRenderBlock >(L"Undergrowth");

renderBlock->distance = vs.distances[i];
renderBlock->program = sp.program;
renderBlock->programParams = renderContext->alloc< render::ProgramParameters >();
renderBlock->indexBuffer = m_indexBuffer->getBufferView();
renderBlock->indexType = render::IndexType::UInt16;
renderBlock->vertexBuffer = m_vertexBuffer->getBufferView();
renderBlock->vertexLayout = m_vertexLayout;
renderBlock->primitive = render::PrimitiveType::Triangles;
renderBlock->offset = 0;
renderBlock->count = 2 * 2;
renderBlock->minIndex = 0;
renderBlock->maxIndex = 3;
renderBlock->instanceCount = batch;

renderBlock->programParams->beginParameters(renderContext);

if (extraParameters)
renderBlock->programParams->attachParameters(extraParameters);

worldRenderPass.setProgramParameters(renderBlock->programParams);
renderBlock->programParams->setVectorArrayParameter(s_handleUndergrowth_Instances1, instanceData1, batch);
renderBlock->programParams->setVectorArrayParameter(s_handleUndergrowth_Instances2, instanceData2, batch);
renderBlock->programParams->endParameters(renderContext);

renderContext->draw(
sp.priority,
renderBlock
);
}
}
auto renderBlock = renderContext->allocNamed< render::IndexedInstancingRenderBlock >(L"Undergrowth");
renderBlock->distance = 10000.0f;
renderBlock->program = sp.program;
renderBlock->programParams = renderContext->alloc< render::ProgramParameters >();
renderBlock->indexBuffer = m_indexBuffer->getBufferView();
renderBlock->indexType = render::IndexType::UInt16;
renderBlock->vertexBuffer = m_vertexBuffer->getBufferView();
renderBlock->vertexLayout = m_vertexLayout;
renderBlock->primitive = render::PrimitiveType::Triangles;
renderBlock->offset = 0;
renderBlock->count = 2 * 2;
renderBlock->minIndex = 0;
renderBlock->maxIndex = 3;
renderBlock->instanceCount = vs.drawInstanceCount;

renderBlock->programParams->beginParameters(renderContext);
worldRenderPass.setProgramParameters(renderBlock->programParams);
renderBlock->programParams->setTextureParameter(s_handleTerrain_Normals, terrain->getNormalMap());
renderBlock->programParams->setTextureParameter(s_handleTerrain_Heightfield, terrain->getHeightMap());
renderBlock->programParams->setTextureParameter(s_handleTerrain_SurfaceAlbedo, terrainComponent->getSurfaceCache(worldRenderView.getIndex())->getBaseTexture());
renderBlock->programParams->setVectorParameter(s_handleTerrain_WorldExtent, terrain->getHeightfield()->getWorldExtent());
renderBlock->programParams->setVectorParameter(s_handleUndergrowth_Eye, eye);
renderBlock->programParams->setFloatParameter(s_handleUndergrowth_MaxDistance, m_layerData.m_spreadDistance + m_clusterSize);
renderBlock->programParams->setBufferViewParameter(s_handleUndergrowth_Plants, vs.plantBuffer->getBufferView());
renderBlock->programParams->setBufferViewParameter(s_handleUndergrowth_Order, vs.orderBuffer->getBufferView());
renderBlock->programParams->endParameters(renderContext);

renderContext->draw(
sp.priority,
renderBlock
);
}

void UndergrowthComponent::updatePatches()
Expand Down
11 changes: 5 additions & 6 deletions code/Terrain/UndergrowthComponent.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* TRAKTOR
* Copyright (c) 2022 Anders Pistol.
* Copyright (c) 2022-2024 Anders Pistol.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
Expand All @@ -9,7 +9,6 @@
#pragma once

#include "Core/Containers/AlignedVector.h"
#include "Core/Containers/BitVector.h"
#include "Core/Math/Vector4.h"
#include "Resource/Proxy.h"
#include "Terrain/TerrainLayerComponent.h"
Expand Down Expand Up @@ -76,14 +75,14 @@ class UndergrowthComponent : public TerrainLayerComponent

struct ViewState
{
AlignedVector< Vector4 > plants;
AlignedVector< float > distances;
BitVector pvs;
uint32_t count;
Ref< render::Buffer > plantBuffer;
Ref< render::Buffer > orderBuffer;
int32_t drawInstanceCount;
};

world::Entity* m_owner = nullptr;
UndergrowthComponentData m_layerData;
Ref< render::IRenderSystem > m_renderSystem;
Ref< const render::IVertexLayout > m_vertexLayout;
Ref< render::Buffer > m_vertexBuffer;
Ref< render::Buffer > m_indexBuffer;
Expand Down
Loading

0 comments on commit 6f841e1

Please sign in to comment.