Skip to content

Commit

Permalink
added more improvements to vct: voxel skipping if radiance from the p…
Browse files Browse the repository at this point in the history
…revious cascade is < margin, blending with bigger cascades based on the distance to center of the current cascade, debugging permutations
  • Loading branch information
steaklive committed Dec 16, 2023
1 parent 3de020c commit f160df0
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 52 deletions.
94 changes: 60 additions & 34 deletions content/shaders/GI/VoxelConeTracingMain.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#define NUM_SHADOW_CASCADES 3
#define NUM_VOXEL_CASCADES 2

#define DEBUG_CASCADE_BLENDING 0
#define DEBUG_SKIPPED_VOXELS 0

static const float4 colorWhite = { 1, 1, 1, 1 };
static const float coneAperture = 0.577f; // 6 cones, 60deg each, tan(30deg) = aperture
static const float3 diffuseConeDirections[] =
Expand Down Expand Up @@ -30,14 +33,7 @@ Texture3D<float4> voxelTextures[NUM_VOXEL_CASCADES] : register(t4);

RWTexture2D<float4> outputTexture : register(u0);

SamplerState LinearSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = BORDER;
AddressV = BORDER;
AddressW = BORDER;
BorderColor = colorWhite;
};
SamplerState LinearSampler : register(s0);

cbuffer VCTMainCB : register(b0)
{
Expand All @@ -52,7 +48,8 @@ cbuffer VCTMainCB : register(b0)
float SamplingFactor;
float VoxelSampleOffset;
float GIPower;
float3 pad1;
float PreviousRadianceDelta;
float2 pad1;
};

float4 GetVoxel(float3 worldPosition, float3 weight, float lod, int cascadeIndex, int cascadeResolution)
Expand Down Expand Up @@ -121,7 +118,9 @@ float4 CalculateIndirectSpecular(float3 worldPos, float3 normal, float4 specular

float4 CalculateIndirectDiffuse(float3 worldPos, float3 normal, out float ao)
{
float4 result = float4(0.0, 0.0, 0.0, 1.0);
float4 totalRadiance = float4(0.0, 0.0, 0.0, 1.0);
float totalAo = 0.0f;
float tempAo = 0.0f;
float3 coneDirection;

float3 upDir = float3(0.0f, 1.0f, 0.0f);
Expand All @@ -130,41 +129,68 @@ float4 CalculateIndirectDiffuse(float3 worldPos, float3 normal, out float ao)

float3 right = normalize(upDir - dot(normal, upDir) * normal);
float3 up = cross(right, normal);

float finalAo = 0.0f;
float tempAo = 0.0f;


uint voxelCascadeResolutions[NUM_VOXEL_CASCADES], empty1, empty2;
for (int cascadeIndex = 0; cascadeIndex < NUM_VOXEL_CASCADES; cascadeIndex++)
voxelTextures[cascadeIndex].GetDimensions(voxelCascadeResolutions[cascadeIndex], empty1, empty2);

for (int i = 0; i < NUM_VOXEL_CONES; i++)
for (int cascadeIndex = NUM_VOXEL_CASCADES - 1; cascadeIndex >= 0; cascadeIndex--)
{
coneDirection = normal;
coneDirection += diffuseConeDirections[i].x * right + diffuseConeDirections[i].z * up;
coneDirection = normalize(coneDirection);
voxelTextures[cascadeIndex].GetDimensions(voxelCascadeResolutions[cascadeIndex], empty1, empty2);

bool wasTracedInLastCascade = false;
for (int cascadeIndex = 0; cascadeIndex < NUM_VOXEL_CASCADES; cascadeIndex++)
float4 currentCascadeRadiance = float4(0.0, 0.0, 0.0, 1.0);
float currentCascadeAo = 0.0f;

const float shift = voxelCascadeResolutions[cascadeIndex] / WorldVoxelScales[cascadeIndex].r * 0.5f;
const float3 voxelGridBoundsMax = VoxelCameraPositions[cascadeIndex].xyz + float3(shift, shift, shift);
const float3 voxelGridBoundsMin = VoxelCameraPositions[cascadeIndex].xyz - float3(shift, shift, shift);

// if prev cascade (bigger) didn't trace anything < margin in that position, we skip re-tracing as an optimization
const bool canSkipVoxel = (cascadeIndex < NUM_VOXEL_CASCADES - 1) && (totalRadiance.x < PreviousRadianceDelta && totalRadiance.y < PreviousRadianceDelta && totalRadiance.z < PreviousRadianceDelta);

#if DEBUG_SKIPPED_VOXELS
if (canSkipVoxel)
totalRadiance = float4(1.0, 0.0, 1.0, 1.0);
#endif

float distToCenter = distance(worldPos.xyz, VoxelCameraPositions[cascadeIndex].xyz);
float distBetweenBounds = abs(voxelGridBoundsMax.x - voxelGridBoundsMin.x);

if (worldPos.x < voxelGridBoundsMin.x || worldPos.y < voxelGridBoundsMin.y || worldPos.z < voxelGridBoundsMin.z ||
worldPos.x > voxelGridBoundsMax.x || worldPos.y > voxelGridBoundsMax.y || worldPos.z > voxelGridBoundsMax.z || canSkipVoxel)
continue; //try to trace from next cascade
else
{
float shift = voxelCascadeResolutions[cascadeIndex] / WorldVoxelScales[cascadeIndex].r * 0.5f;
float3 voxelGridBoundsMax = VoxelCameraPositions[cascadeIndex].xyz + float3(shift, shift, shift);
float3 voxelGridBoundsMin = VoxelCameraPositions[cascadeIndex].xyz - float3(shift, shift, shift);
for (int i = 0; i < NUM_VOXEL_CONES; i++)
{
coneDirection = normal;
coneDirection += diffuseConeDirections[i].x * right + diffuseConeDirections[i].z * up;
coneDirection = normalize(coneDirection);

if (worldPos.x < voxelGridBoundsMin.x || worldPos.y < voxelGridBoundsMin.y || worldPos.z < voxelGridBoundsMin.z ||
worldPos.x > voxelGridBoundsMax.x || worldPos.y > voxelGridBoundsMax.y || worldPos.z > voxelGridBoundsMax.z || wasTracedInLastCascade)
continue; //try to trace from next cascade
currentCascadeRadiance += TraceCone(worldPos, normal, coneDirection, coneAperture, tempAo, true, cascadeIndex, voxelCascadeResolutions[cascadeIndex]) * diffuseConeWeights[i];
currentCascadeAo += tempAo * diffuseConeWeights[i];
}

if (cascadeIndex == NUM_VOXEL_CASCADES - 1)
{
#if DEBUG_CASCADE_BLENDING
totalRadiance += float4(1.0, 0.0, 0.0, 1.0);
#else
totalRadiance += currentCascadeRadiance;
#endif
totalAo += currentCascadeAo;
}
else
{
result += TraceCone(worldPos, normal, coneDirection, coneAperture, tempAo, true, cascadeIndex, voxelCascadeResolutions[cascadeIndex]) * diffuseConeWeights[i];
finalAo += tempAo * diffuseConeWeights[i];
wasTracedInLastCascade = true;
#if DEBUG_CASCADE_BLENDING
currentCascadeRadiance = float4(0.0, 0.0, 0.0, 1.0);
#endif
float blendFactor = distToCenter / (0.5f * distBetweenBounds); // how much to blend from the bounds of the cascade: the further from the center, the more you blend with bigger cascades
totalAo = lerp(currentCascadeAo, totalAo, blendFactor);
totalRadiance = lerp(currentCascadeRadiance,totalRadiance, blendFactor);
}
}
}

ao = finalAo;
return IndirectDiffuseStrength * result;
ao = totalAo;
return IndirectDiffuseStrength * totalRadiance;
}

[numthreads(8, 8, 1)]
Expand Down
24 changes: 9 additions & 15 deletions source/EveryRay_Core/ER_Illumination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,8 @@ namespace EveryRay_Core {
mVoxelConeTracingMainConstantBuffer.Data.SamplingFactor = mVCTSamplingFactor;
mVoxelConeTracingMainConstantBuffer.Data.VoxelSampleOffset = mVCTVoxelSampleOffset;
mVoxelConeTracingMainConstantBuffer.Data.GIPower = mVCTGIPower;
mVoxelConeTracingMainConstantBuffer.Data.pad0 = XMFLOAT3(0, 0, 0);
mVoxelConeTracingMainConstantBuffer.Data.PreviousRadianceDelta = mVCTPreviousRadianceDelta;
mVoxelConeTracingMainConstantBuffer.Data.pad0 = XMFLOAT2(0.0, 0.0);
mVoxelConeTracingMainConstantBuffer.ApplyChanges(rhi);

rhi->SetRootSignature(mVCTRS, true);
Expand Down Expand Up @@ -802,6 +803,7 @@ namespace EveryRay_Core {
{
ImGui::Checkbox("VCT GI Enabled", &mIsVCTEnabled);
ImGui::SliderFloat("VCT GI Intensity", &mVCTGIPower, 0.0f, 5.0f);
ImGui::SliderFloat("VCT Min Radiance Margin", &mVCTPreviousRadianceDelta, 0.0f, 0.1f);
ImGui::SliderFloat("VCT Diffuse Strength", &mVCTIndirectDiffuseStrength, 0.0f, 1.0f);
ImGui::SliderFloat("VCT Specular Strength", &mVCTIndirectSpecularStrength, 0.0f, 1.0f);
ImGui::SliderFloat("VCT Max Cone Trace Dist", &mVCTMaxConeTraceDistance, 0.0f, 2500.0f);
Expand Down Expand Up @@ -1167,20 +1169,12 @@ namespace EveryRay_Core {
if (!objectInfo.second->IsInVoxelization())
continue;

auto aabbObj = objectInfo.second->GetLocalAABB();
XMFLOAT3 position;
ER_MatrixHelper::GetTranslation(objectInfo.second->GetTransformationMatrix(), position);
aabbObj.first.x += position.x;
aabbObj.first.y += position.y;
aabbObj.first.z += position.z;
aabbObj.second.x += position.x;
aabbObj.second.y += position.y;
aabbObj.second.z += position.z;

bool isColliding =
(aabbObj.first.x <= mWorldVoxelCascadesAABBs[cascade].second.x && aabbObj.second.x >= mWorldVoxelCascadesAABBs[cascade].first.x) &&
(aabbObj.first.y <= mWorldVoxelCascadesAABBs[cascade].second.y && aabbObj.second.y >= mWorldVoxelCascadesAABBs[cascade].first.y) &&
(aabbObj.first.z <= mWorldVoxelCascadesAABBs[cascade].second.z && aabbObj.second.z >= mWorldVoxelCascadesAABBs[cascade].first.z);
ER_AABB& aabbObj = objectInfo.second->GetGlobalAABB();

bool isColliding = objectInfo.second->IsInstanced() ||
((aabbObj.first.x <= mWorldVoxelCascadesAABBs[cascade].second.x && aabbObj.second.x >= mWorldVoxelCascadesAABBs[cascade].first.x) &&
(aabbObj.first.y <= mWorldVoxelCascadesAABBs[cascade].second.y && aabbObj.second.y >= mWorldVoxelCascadesAABBs[cascade].first.y) &&
(aabbObj.first.z <= mWorldVoxelCascadesAABBs[cascade].second.z && aabbObj.second.z >= mWorldVoxelCascadesAABBs[cascade].first.z));

auto it = mVoxelizationObjects[cascade].find(objectInfo.first);
if (isColliding && (it == mVoxelizationObjects[cascade].end()))
Expand Down
8 changes: 5 additions & 3 deletions source/EveryRay_Core/ER_Illumination.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ namespace EveryRay_Core
float SamplingFactor;
float VoxelSampleOffset;
float GIPower;
XMFLOAT3 pad0;
float PreviousRadianceDelta;
XMFLOAT2 pad0;
};
struct ER_ALIGN_GPU_BUFFER CompositeTotalIlluminationCB
{
Expand Down Expand Up @@ -298,13 +299,14 @@ namespace EveryRay_Core
ER_RenderableAABB* mDebugVoxelZonesGizmos[NUM_VOXEL_GI_CASCADES] = { nullptr, nullptr };
float mWorldVoxelScales[NUM_VOXEL_GI_CASCADES] = { 2.0f, 0.5f };

float mVCTIndirectDiffuseStrength = 0.2f;
float mVCTIndirectDiffuseStrength = 0.4f;
float mVCTIndirectSpecularStrength = 1.0f;
float mVCTMaxConeTraceDistance = 100.0f;
float mVCTAoFalloff = 15.0f;
float mVCTAoFalloff = 0.15f;
float mVCTSamplingFactor = 0.5f;
float mVCTVoxelSampleOffset = 0.0f;
float mVCTGIPower = 1.0f;
float mVCTPreviousRadianceDelta = 0.01f;
float mVCTDownscaleFactor = 0.5f; // % from full-res RT
bool mIsVCTVoxelCameraPositionsUpdated[NUM_VOXEL_GI_CASCADES] = { true, true }; // whether the volume was updated in the last frame
bool mIsVCTAlwaysUpdated = false; // update volumes every frame (only for debugging)
Expand Down

0 comments on commit f160df0

Please sign in to comment.