Skip to content

Commit

Permalink
fixed light probe on-terrain placement on DX12:
Browse files Browse the repository at this point in the history
- implemented a delayed GPU readback via ReadbackPlacedPositionsOnInitEvent in ER_LightProbesManager::PlaceProbesOnTerrain()
- split PlaceOnTerrainData cbuffer into 2: PlaceOnTerrainGlobalData and PlaceOnTerrainPropData (used as root constant)
- fixed a crash in ER_RHI::BeginEventTag()/EndEventTag()
bumped version name in ER_Utility.h to 1.1
  • Loading branch information
steaklive committed Mar 16, 2024
1 parent bc31339 commit 2384385
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 62 deletions.
22 changes: 13 additions & 9 deletions content/shaders/Terrain/PlaceObjectsOnTerrain.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@
cbuffer CBufferTerrain : register(b0)
{
float HeightScale;
float SplatChannel;
float TerrainTileCount;
float PlacementHeightDelta;
}

cbuffer CBufferTerrainProps : register(b1)
{
uint SplatChannel;
uint PlacementHeightDelta;
}

struct TerrainTileData
Expand Down Expand Up @@ -237,21 +241,21 @@ float FindHeightFromHeightmap(float x, float z, int tileIndex)
return height * HeightScale;
}

bool IsOnSplatMap(float x, float z, int tileIndex, float channel)
bool IsOnSplatMap(float x, float z, int tileIndex, uint channel)
{
float2 uv = GetTextureCoordinates(x, z, tileIndex);
uv.y = 1.0f - uv.y;

float percentage = 0.2f;

float4 value = TerrainTilesSplatTextures.SampleLevel(LinearSampler, float3(uv, tileIndex), 0);
if (channel == 0.0f && value.r > percentage)
if (channel == 0 && value.r > percentage)
return true;
else if (channel == 1.0f && value.g > percentage)
else if (channel == 1u && value.g > percentage)
return true;
else if (channel == 2.0f && value.b > percentage)
else if (channel == 2u && value.b > percentage)
return true;
else if (channel == 3.0f && value.a > percentage)
else if (channel == 3u && value.a > percentage)
return true;
else
return false;
Expand All @@ -275,11 +279,11 @@ void CSMain(uint3 threadID : SV_DispatchThreadID, uint groupIndex : SV_GroupInde

if (tileIndex >= 0)
{
if (SplatChannel == -1.0f || IsOnSplatMap(x, z, tileIndex, SplatChannel))
if (SplatChannel == 255 || IsOnSplatMap(x, z, tileIndex, SplatChannel))
#if USE_RAYCASTING
InputOutputPositions[threadID.x].y = FindHeightFromPosition(vertexCount, x, z);
#else
InputOutputPositions[threadID.x].y = FindHeightFromHeightmap(x, z, tileIndex) - PlacementHeightDelta;
InputOutputPositions[threadID.x].y = FindHeightFromHeightmap(x, z, tileIndex) - asfloat(PlacementHeightDelta);
#endif
else
InputOutputPositions[threadID.x].y = -999.0f; //culled
Expand Down
91 changes: 58 additions & 33 deletions source/EveryRay_Core/ER_LightProbesManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,33 +241,25 @@ namespace EveryRay_Core

// all probes positions GPU buffer
{
XMFLOAT4* diffuseProbesPositionsCPUBuffer = new XMFLOAT4[mDiffuseProbesCountTotal];
assert(!mDiffuseProbesPositionsTempCPUBuffer);

mDiffuseProbesPositionsTempCPUBuffer = new XMFLOAT4[mDiffuseProbesCountTotal];
for (int probeIndex = 0; probeIndex < mDiffuseProbesCountTotal; probeIndex++)
diffuseProbesPositionsCPUBuffer[probeIndex] = XMFLOAT4(mDiffuseProbes[probeIndex].GetPosition().x, mDiffuseProbes[probeIndex].GetPosition().y, mDiffuseProbes[probeIndex].GetPosition().z, 1.0);
mDiffuseProbesPositionsTempCPUBuffer[probeIndex] = XMFLOAT4(mDiffuseProbes[probeIndex].GetPosition().x, mDiffuseProbes[probeIndex].GetPosition().y, mDiffuseProbes[probeIndex].GetPosition().z, 1.0);

mDiffuseProbesPositionsGPUBuffer = rhi->CreateGPUBuffer("ER_RHI_GPUBuffer: diffuse probes positions buffer");
mDiffuseProbesPositionsGPUBuffer->CreateGPUBufferResource(rhi, diffuseProbesPositionsCPUBuffer, mDiffuseProbesCountTotal, sizeof(XMFLOAT4), mIsPlacedOnTerrain, ER_BIND_SHADER_RESOURCE, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);
mDiffuseProbesPositionsGPUBuffer->CreateGPUBufferResource(rhi, mDiffuseProbesPositionsTempCPUBuffer, mDiffuseProbesCountTotal, sizeof(XMFLOAT4), mIsPlacedOnTerrain, ER_BIND_SHADER_RESOURCE, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);

if (mIsPlacedOnTerrain)
{
mDiffuseInputPositionsOnTerrainBuffer = rhi->CreateGPUBuffer("ER_RHI_GPUBuffer: On-terrain placement input positions buffer (diffuse probes)");
mDiffuseInputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, diffuseProbesPositionsCPUBuffer, mDiffuseProbesCountTotal, sizeof(XMFLOAT4), false , ER_BIND_UNORDERED_ACCESS, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);
mDiffuseInputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, mDiffuseProbesPositionsTempCPUBuffer, mDiffuseProbesCountTotal, sizeof(XMFLOAT4), false , ER_BIND_UNORDERED_ACCESS, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);

mDiffuseOutputPositionsOnTerrainBuffer = rhi->CreateGPUBuffer("ER_RHI_GPUBuffer: On-terrain placement output positions buffer (diffuse probes)");
mDiffuseOutputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, diffuseProbesPositionsCPUBuffer, mDiffuseProbesCountTotal, sizeof(XMFLOAT4), false, ER_BIND_NONE, 0x10000L | 0x20000L /*legacy from DX11*/, ER_RESOURCE_MISC_BUFFER_STRUCTURED); //should be STAGING

PlaceProbesOnTerrain(core, mDiffuseOutputPositionsOnTerrainBuffer, mDiffuseInputPositionsOnTerrainBuffer, diffuseProbesPositionsCPUBuffer, mDiffuseProbesCountTotal, mTerrainPlacementHeightDeltaDiffuseProbes);

rhi->UpdateBuffer(mDiffuseProbesPositionsGPUBuffer, (void*)diffuseProbesPositionsCPUBuffer, mDiffuseProbesCountTotal * sizeof(XMFLOAT4));
mDiffuseOutputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, mDiffuseProbesPositionsTempCPUBuffer, mDiffuseProbesCountTotal, sizeof(XMFLOAT4), false, ER_BIND_NONE, 0x10000L | 0x20000L /*legacy from DX11*/, ER_RESOURCE_MISC_BUFFER_STRUCTURED); //should be STAGING

for (int i = 0; i < mDiffuseProbesCountTotal; i++)
mDiffuseProbes[i].SetPosition(XMFLOAT3(diffuseProbesPositionsCPUBuffer[i].x, diffuseProbesPositionsCPUBuffer[i].y, diffuseProbesPositionsCPUBuffer[i].z));

DeleteObject(mDiffuseInputPositionsOnTerrainBuffer);
DeleteObject(mDiffuseOutputPositionsOnTerrainBuffer);
PlaceProbesOnTerrain(core, DIFFUSE_PROBE, mDiffuseOutputPositionsOnTerrainBuffer, mDiffuseInputPositionsOnTerrainBuffer, mDiffuseProbesPositionsTempCPUBuffer, mDiffuseProbesCountTotal, mTerrainPlacementHeightDeltaDiffuseProbes);
}

DeleteObjects(diffuseProbesPositionsCPUBuffer);
}

// probe cell's indices GPU buffer, tex. array indices GPU/CPU buffers
Expand Down Expand Up @@ -396,33 +388,24 @@ namespace EveryRay_Core

// all probes positions GPU buffer
{
XMFLOAT4* specularProbesPositionsCPUBuffer = new XMFLOAT4[mSpecularProbesCountTotal];
assert(!mSpecularProbesPositionsTempCPUBuffer);
mSpecularProbesPositionsTempCPUBuffer = new XMFLOAT4[mSpecularProbesCountTotal];

for (int probeIndex = 0; probeIndex < mSpecularProbesCountTotal; probeIndex++)
specularProbesPositionsCPUBuffer[probeIndex] = XMFLOAT4(mSpecularProbes[probeIndex].GetPosition().x,mSpecularProbes[probeIndex].GetPosition().y,mSpecularProbes[probeIndex].GetPosition().z, 1.0);
mSpecularProbesPositionsTempCPUBuffer[probeIndex] = XMFLOAT4(mSpecularProbes[probeIndex].GetPosition().x,mSpecularProbes[probeIndex].GetPosition().y,mSpecularProbes[probeIndex].GetPosition().z, 1.0);
mSpecularProbesPositionsGPUBuffer = rhi->CreateGPUBuffer("ER_RHI_GPUBuffer: specular probes positions buffer");
mSpecularProbesPositionsGPUBuffer->CreateGPUBufferResource(rhi, specularProbesPositionsCPUBuffer, mSpecularProbesCountTotal, sizeof(XMFLOAT4), mIsPlacedOnTerrain, ER_BIND_SHADER_RESOURCE, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);
mSpecularProbesPositionsGPUBuffer->CreateGPUBufferResource(rhi, mSpecularProbesPositionsTempCPUBuffer, mSpecularProbesCountTotal, sizeof(XMFLOAT4), mIsPlacedOnTerrain, ER_BIND_SHADER_RESOURCE, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);

if (mIsPlacedOnTerrain)
{
mSpecularInputPositionsOnTerrainBuffer = rhi->CreateGPUBuffer("ER_RHI_GPUBuffer: On-terrain placement input positions buffer (specular probes)");
mSpecularInputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, specularProbesPositionsCPUBuffer, mSpecularProbesCountTotal, sizeof(XMFLOAT4), false, ER_BIND_UNORDERED_ACCESS, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);
mSpecularInputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, mSpecularProbesPositionsTempCPUBuffer, mSpecularProbesCountTotal, sizeof(XMFLOAT4), false, ER_BIND_UNORDERED_ACCESS, 0, ER_RESOURCE_MISC_BUFFER_STRUCTURED);

mSpecularOutputPositionsOnTerrainBuffer = rhi->CreateGPUBuffer("ER_RHI_GPUBuffer: On-terrain placement output positions buffer (specular probes)");
mSpecularOutputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, specularProbesPositionsCPUBuffer, mSpecularProbesCountTotal, sizeof(XMFLOAT4), false, ER_BIND_NONE, 0x10000L | 0x20000L /*legacy from DX11*/, ER_RESOURCE_MISC_BUFFER_STRUCTURED); //should be STAGING

PlaceProbesOnTerrain(game, mSpecularOutputPositionsOnTerrainBuffer, mSpecularInputPositionsOnTerrainBuffer, specularProbesPositionsCPUBuffer, mSpecularProbesCountTotal, mTerrainPlacementHeightDeltaSpecularProbes);
mSpecularOutputPositionsOnTerrainBuffer->CreateGPUBufferResource(rhi, mSpecularProbesPositionsTempCPUBuffer, mSpecularProbesCountTotal, sizeof(XMFLOAT4), false, ER_BIND_NONE, 0x10000L | 0x20000L /*legacy from DX11*/, ER_RESOURCE_MISC_BUFFER_STRUCTURED); //should be STAGING

rhi->UpdateBuffer(mSpecularProbesPositionsGPUBuffer, (void*)specularProbesPositionsCPUBuffer, mSpecularProbesCountTotal * sizeof(XMFLOAT4));

for (int i = 0; i < mSpecularProbesCountTotal; i++)
mSpecularProbes[i].SetPosition(XMFLOAT3(specularProbesPositionsCPUBuffer[i].x, specularProbesPositionsCPUBuffer[i].y, specularProbesPositionsCPUBuffer[i].z));

DeleteObject(mSpecularInputPositionsOnTerrainBuffer);
DeleteObject(mSpecularOutputPositionsOnTerrainBuffer);
PlaceProbesOnTerrain(game, SPECULAR_PROBE, mSpecularOutputPositionsOnTerrainBuffer, mSpecularInputPositionsOnTerrainBuffer, mSpecularProbesPositionsTempCPUBuffer, mSpecularProbesCountTotal, mTerrainPlacementHeightDeltaSpecularProbes);
}

DeleteObjects(specularProbesPositionsCPUBuffer);
}

// probe cell's indices GPU buffer, tex. array indices GPU/CPU buffers
Expand Down Expand Up @@ -834,6 +817,12 @@ namespace EveryRay_Core
oldInstancedData[i].World._44 = isCulled ? 1.0f : 0.0f;
//writing cubemap index to [0][0] of world instanced matrix (since we don't need scale)
oldInstancedData[i].World._11 = -1.0f;
//updating position
const XMFLOAT3& pos = probes[i].GetPosition();
oldInstancedData[i].World._41 = pos.x;
oldInstancedData[i].World._42 = pos.y;
oldInstancedData[i].World._43 = pos.z;

if (!isCulled)
{
if (aType == DIFFUSE_PROBE)
Expand Down Expand Up @@ -885,6 +874,12 @@ namespace EveryRay_Core

void ER_LightProbesManager::UpdateProbes(ER_Core& game)
{
// delete temp CPU buffers in the first frame (we should have the positions in probes already)
if (mDiffuseProbesPositionsTempCPUBuffer)
DeleteObjects(mDiffuseProbesPositionsTempCPUBuffer);
if (mSpecularProbesPositionsTempCPUBuffer)
DeleteObjects(mSpecularProbesPositionsTempCPUBuffer);

//int difProbeCellIndexCamera = GetCellIndex(mMainCamera.Position(), DIFFUSE_PROBE);
if (mDistanceBetweenSpecularProbes > 0)
assert(mMaxSpecularProbesInVolumeCount > 0);
Expand All @@ -893,7 +888,7 @@ namespace EveryRay_Core
UpdateProbesByType(game, SPECULAR_PROBE);
}

void ER_LightProbesManager::PlaceProbesOnTerrain(ER_Core& game, ER_RHI_GPUBuffer* outputBuffer, ER_RHI_GPUBuffer* inputBuffer, XMFLOAT4* positions, int positionsCount, float customDampDelta /*= FLT_MAX*/)
void ER_LightProbesManager::PlaceProbesOnTerrain(ER_Core& game, ER_ProbeType aType, ER_RHI_GPUBuffer* outputBuffer, ER_RHI_GPUBuffer* inputBuffer, XMFLOAT4* positions, int positionsCount, float customDampDelta /*= FLT_MAX*/)
{
assert(mIsPlacedOnTerrain);

Expand All @@ -902,5 +897,35 @@ namespace EveryRay_Core
throw ER_CoreException("You want to place light probes on terrain but terrain is not found in the scene!");

terrain->PlaceOnTerrain(outputBuffer, inputBuffer, positions, positionsCount, TerrainSplatChannels::NONE, nullptr, 0, customDampDelta);

ER_RHI_GPUBuffer* finalGPUBuffer = (aType == DIFFUSE_PROBE) ? mDiffuseProbesPositionsGPUBuffer : mSpecularProbesPositionsGPUBuffer;

#ifndef ER_PLATFORM_WIN64_DX11
const std::string probeTypeName = (aType == DIFFUSE_PROBE) ? "diffuse" : "specular";
const std::string eventName = "On-terrain placement callback - placement of probes: " + probeTypeName;
terrain->ReadbackPlacedPositionsOnInitEvent->AddListener(eventName,
[&, aType, finalGPUBuffer, outputBuffer, inputBuffer, positions, positionsCount, rhi = game.GetRHI(), sandbox = game.GetLevel()](ER_Terrain* aTerrain)
{
assert(aTerrain);
aTerrain->ReadbackPlacedPositions(outputBuffer, inputBuffer, positions, positionsCount);

rhi->UpdateBuffer(finalGPUBuffer, (void*)positions, positionsCount * sizeof(XMFLOAT4), true);

if (aType == DIFFUSE_PROBE)
for (int i = 0; i < positionsCount; i++)
sandbox->mLightProbesManager->SetDiffuseProbePosition(i, XMFLOAT3(positions[i].x, positions[i].y, positions[i].z));
else
for (int i = 0; i < positionsCount; i++)
sandbox->mLightProbesManager->SetSpecularProbePosition(i, XMFLOAT3(positions[i].x, positions[i].y, positions[i].z));
}
);
#else
std::vector<ER_LightProbe>& probes = (aType == DIFFUSE_PROBE) ? mDiffuseProbes : mSpecularProbes;

game.GetRHI()->UpdateBuffer(finalGPUBuffer, (void*)positions, positionsCount * sizeof(XMFLOAT4));

for (int i = 0; i < positionsCount; i++)
probes[i].SetPosition(XMFLOAT3(positions[i].x, positions[i].y, positions[i].z));
#endif
}
}
8 changes: 7 additions & 1 deletion source/EveryRay_Core/ER_LightProbesManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ namespace EveryRay_Core
bool IsEnabled() { return mEnabled; }
bool AreGlobalProbesReady() { return mGlobalDiffuseProbeReady && mGlobalSpecularProbeReady; }

void SetDiffuseProbePosition(int index, const XMFLOAT3& pos) { mDiffuseProbes[index].SetPosition(pos); }
void SetSpecularProbePosition(int index, const XMFLOAT3& pos) { mSpecularProbes[index].SetPosition(pos); }

bool mDebugDiscardCulledProbes = false;//used in DebugLightProbeMaterial
private:
void SetupGlobalDiffuseProbe(ER_Core& game, ER_Camera& camera, ER_Scene* scene, ER_DirectionalLight* light, ER_ShadowMapper* shadowMapper);
Expand All @@ -93,7 +96,8 @@ namespace EveryRay_Core
void AddProbeToCells(ER_LightProbe& aProbe, ER_ProbeType aType, const XMFLOAT3& minBounds, const XMFLOAT3& maxBounds);
bool IsProbeInCell(ER_LightProbe& aProbe, ER_LightProbeCell& aCell, ER_AABB& aCellBounds);
void UpdateProbesByType(ER_Core& game, ER_ProbeType aType);
void PlaceProbesOnTerrain(ER_Core& game, ER_RHI_GPUBuffer* outputBuffer, ER_RHI_GPUBuffer* inputBuffer, XMFLOAT4* positions, int positionsCount, float customDampDelta = FLT_MAX);
void PlaceProbesOnTerrain(ER_Core& game, ER_ProbeType aType, ER_RHI_GPUBuffer* outputBuffer, ER_RHI_GPUBuffer* inputBuffer,
XMFLOAT4* positions, int positionsCount, float customDampDelta = FLT_MAX);

ER_QuadRenderer* mQuadRenderer = nullptr;
ER_Camera& mMainCamera;
Expand All @@ -111,6 +115,7 @@ namespace EveryRay_Core
std::string mDiffuseDebugLightProbePassPSOName = "ER_RHI_GPUPipelineStateObject: Light Probes Manager - Diffuse Debug Probe Pass";
ER_RHI_GPUBuffer* mDiffuseProbesCellsIndicesGPUBuffer = nullptr;
ER_RHI_GPUBuffer* mDiffuseProbesPositionsGPUBuffer = nullptr;
XMFLOAT4* mDiffuseProbesPositionsTempCPUBuffer = nullptr;
ER_RHI_GPUBuffer* mDiffuseInputPositionsOnTerrainBuffer = nullptr;
ER_RHI_GPUBuffer* mDiffuseOutputPositionsOnTerrainBuffer = nullptr;
ER_RHI_GPUBuffer* mDiffuseProbesSphericalHarmonicsGPUBuffer = nullptr;
Expand Down Expand Up @@ -140,6 +145,7 @@ namespace EveryRay_Core
ER_RHI_GPUBuffer* mSpecularProbesTexArrayIndicesGPUBuffer = nullptr;
ER_RHI_GPUBuffer* mSpecularProbesCellsIndicesGPUBuffer = nullptr;
ER_RHI_GPUBuffer* mSpecularProbesPositionsGPUBuffer = nullptr;
XMFLOAT4* mSpecularProbesPositionsTempCPUBuffer = nullptr;
ER_RHI_GPUBuffer* mSpecularInputPositionsOnTerrainBuffer = nullptr;
ER_RHI_GPUBuffer* mSpecularOutputPositionsOnTerrainBuffer = nullptr;
ER_RHI_GPUTexture* mTempSpecularCubemapFacesRT = nullptr;
Expand Down
Loading

0 comments on commit 2384385

Please sign in to comment.