Added citybuilder and cloud pass.

This commit is contained in:
Justin Marshall
2026-05-28 01:09:16 -07:00
parent 5d2cb8640d
commit a7e7e8edbc
30 changed files with 58019 additions and 36996 deletions
+132 -15
View File
@@ -1582,7 +1582,8 @@ static int glRaytracingUploadMeshBuffers(glRaytracingMeshRecord_t* mesh);
static int glRaytracingBuildDirtyMeshesInternal(void)
{
std::vector<glRaytracingMeshRecord_t*> dirtyMeshes;
static thread_local std::vector<glRaytracingMeshRecord_t*> dirtyMeshes;
dirtyMeshes.clear();
dirtyMeshes.reserve(g_glRaytracingScene.meshes.size());
for (size_t i = 0; i < g_glRaytracingScene.meshes.size(); ++i)
@@ -1608,7 +1609,8 @@ static int glRaytracingBuildDirtyMeshesInternal(void)
int newBlasIndex;
};
std::vector<glRaytracingMeshBuildInfo_t> builds;
static thread_local std::vector<glRaytracingMeshBuildInfo_t> builds;
builds.clear();
builds.resize(dirtyMeshes.size());
for (size_t i = 0; i < dirtyMeshes.size(); ++i)
@@ -2570,6 +2572,11 @@ struct glRaytracingLightingConstants_t
uint32_t secondaryCorrectionBudget;
float secondaryLightCompensation;
uint32_t historyReset;
uint32_t externalDenoiser;
float giAmount;
float worldGrimeAmount;
uint32_t pad2;
};
struct glRaytracingMeshMetadata_t
@@ -2853,6 +2860,10 @@ cbuffer LightingCB : register(b0)
uint gSecondaryCorrectionBudget;
float gSecondaryLightCompensation;
uint gHistoryReset;
uint gExternalDenoiser;
float gGiAmount;
float gWorldGrimeAmount;
uint gPadding2;
};
StructuredBuffer<Light> gLights : register(t0);
@@ -3338,6 +3349,53 @@ float Hash12(float2 p)
return frac((p3.x + p3.y) * p3.z);
}
float Hash13(float3 p)
{
p = frac(p * 0.1031);
p += dot(p, p.yzx + 33.33);
return frac((p.x + p.y) * p.z);
}
float ValueNoise3D(float3 p)
{
float3 i = floor(p);
float3 f = frac(p);
f = f * f * (3.0 - 2.0 * f);
float n000 = Hash13(i + float3(0, 0, 0));
float n100 = Hash13(i + float3(1, 0, 0));
float n010 = Hash13(i + float3(0, 1, 0));
float n110 = Hash13(i + float3(1, 1, 0));
float n001 = Hash13(i + float3(0, 0, 1));
float n101 = Hash13(i + float3(1, 0, 1));
float n011 = Hash13(i + float3(0, 1, 1));
float n111 = Hash13(i + float3(1, 1, 1));
float nx00 = lerp(n000, n100, f.x);
float nx10 = lerp(n010, n110, f.x);
float nx01 = lerp(n001, n101, f.x);
float nx11 = lerp(n011, n111, f.x);
float nxy0 = lerp(nx00, nx10, f.y);
float nxy1 = lerp(nx01, nx11, f.y);
return lerp(nxy0, nxy1, f.z);
}
void ApplyWorldGrime(float3 worldPos, float cavity, float ao, bool isSkeletal, inout float3 baseAlbedo, inout float3 specularAlbedo)
{
if (isSkeletal || gWorldGrimeAmount <= 0.0001)
return;
float crevice = saturate((1.0 - cavity) * 1.35 + (1.0 - ao) * 0.55);
float largeNoise = ValueNoise3D(worldPos * 0.025);
float fineNoise = ValueNoise3D(worldPos * 0.11 + float3(17.0, 41.0, 9.0));
float grimeMask = saturate(crevice * (0.65 + 0.55 * largeNoise) + fineNoise * 0.18);
float amount = saturate(grimeMask * gWorldGrimeAmount);
float3 dirtTint = float3(0.36, 0.31, 0.24);
baseAlbedo = lerp(baseAlbedo, baseAlbedo * dirtTint, amount);
specularAlbedo *= lerp(1.0, 0.55, amount);
}
float2 Hammersley2D(uint i, uint N, float rand)
{
float e1 = frac((float)i / (float)N + rand);
@@ -4346,6 +4404,24 @@ uint InitSpatialRng(uint2 pixel, float3 worldPos, uint salt)
return PcgHash(seed) | 1u;
}
uint InitSurfaceStableRng(uint2 pixel, float3 worldPos, float3 normal, uint sampleIndex, uint frameIndex)
{
if (gExternalDenoiser == 0u)
return InitRng(pixel, frameIndex, sampleIndex);
uint3 cell = (uint3)floor(abs(worldPos) * 16.0 + 0.5);
uint3 ncell = (uint3)floor(saturate(normal * 0.5 + 0.5) * 255.0 + 0.5);
uint seed =
cell.x * 73856093u ^
cell.y * 19349663u ^
cell.z * 83492791u ^
ncell.x * 1597334677u ^
ncell.y * 3812015801u ^
ncell.z * 2798796415u ^
sampleIndex * 0x9E3779B9u;
return PcgHash(seed) | 1u;
}
float Rand(inout uint rng)
{
rng = PcgHash(rng);
@@ -5587,7 +5663,8 @@ float2 GetStratifiedBounceXi(uint2 pixel, float3 worldPos, float3 pathNormal, ui
{
uint spp = max(gSamplesPerPixel, 1u);
uint sequenceLength = max(spp * 64u, 64u);
uint sequenceIndex = (sampleIndex + (gFrameIndex & 63u) * spp) % sequenceLength;
uint rngFrameIndex = (gEnableDenoiser != 0u && gExternalDenoiser == 0u) ? gFrameIndex : 0u;
uint sequenceIndex = (sampleIndex + (rngFrameIndex & 63u) * spp) % sequenceLength;
float rand = Hash12(
(float2)pixel +
@@ -6212,21 +6289,24 @@ void RayGen()
// All four of these are deterministic for this pixel. Compute them once,
// then reuse them for every stochastic GI sample.
float cavity = ComputeCavity(pixel, worldPos, N);
const bool externalCharacterPixel = (gExternalDenoiser != 0u) && isSkeletal;
float cavity = externalCharacterPixel ? 1.0 : ComputeCavity(pixel, worldPos, N);
if (isSkeletal)
cavity = lerp(cavity, 1.0, 0.65);
float ao = ComputeAmbientOcclusion(worldPos, N, pixel, isSkeletal);
float ao = externalCharacterPixel ? 1.0 : ComputeAmbientOcclusion(worldPos, N, pixel, isSkeletal);
float skyVis = 0; //ComputeSkyVisibility(worldPos, N, pixel);
float ambientSkyVis = 0; //TraceStraightUpToSky(worldPos, N);
float microShadow = lerp(0.75, 1.0, cavity);
ApplyWorldGrime(worldPos, cavity, ao, isSkeletal, baseAlbedo, specularAlbedo);
float3 reactiveFinalGather = 0.0;
uint rngFrameIndex = (gEnableDenoiser != 0u && gExternalDenoiser == 0u) ? gFrameIndex : 0u;
if (gMaxBounces > 1u)
{
// Evaluate this deterministic screen-space irradiance reuse once per
// pixel, not once per SPP. That makes the GI more responsive without
// multiplying the light-list work inside the stochastic sample loop.
uint gatherRng = InitRng(pixel, gFrameIndex, 1337u);
uint gatherRng = InitSurfaceStableRng(pixel, worldPos, N, 1337u, rngFrameIndex);
reactiveFinalGather = EstimateReactiveScreenSpaceFinalGather(
pixel,
worldPos,
@@ -6257,17 +6337,17 @@ void RayGen()
// Only the indirect bounce path uses per-SPP randomness now. Direct lights,
// AO, sky visibility, cavity, and final gather are deterministic and should
// not be re-traced spp times.
if (gMaxBounces > 1u)
if (gMaxBounces > 1u && !externalCharacterPixel)
{
float3 indirectAccum = 0.0;
[loop]
for (uint s = 0; s < spp; ++s)
{
// Frame-vary the GI path now that a temporal accumulator is present.
// This lets the stochastic light subset, sky sample, and diffuse path
// converge instead of staying locked to one noisy sample pattern.
uint rng = InitRng(pixel, gFrameIndex, s);
// Frame-vary only when the internal temporal accumulator is active.
// External denoisers get a surface-stable raw GI pattern so texture
// detail does not boil under reconstruction.
uint rng = InitSurfaceStableRng(pixel, worldPos, N, s, rngFrameIndex);
indirectAccum += EstimatePathTracedIndirectBounce(
pixel,
worldPos,
@@ -6279,7 +6359,7 @@ void RayGen()
}
float3 indirectLighting = indirectAccum / (float)spp;
lightingAccum += ApplyPrimaryDiffusePost(indirectLighting, ao, microShadow, isSkeletal);
lightingAccum += ApplyPrimaryDiffusePost(indirectLighting, ao, microShadow, isSkeletal) * gGiAmount;
}
uint reflectionRng = InitRng(pixel, 0u, 0x5EECu);
@@ -6301,11 +6381,10 @@ void RayGen()
{
// reactiveFinalGather is incoming indirect radiance. Apply the primary
// diffuse albedo here, matching the regular lighting path.
finalColor += baseAlbedo * reactiveFinalGather;
finalColor += baseAlbedo * reactiveFinalGather * gGiAmount;
}
float outputAo = isSkeletal ? lerp(ao, 1.0, 0.55) : ao;
finalColor *= clamp(outputAo + 0.3, 0.0, 1.0);
finalColor += subsurfaceAccum;
// Volumetric light scattering is radiance in the camera ray, not surface
@@ -6321,7 +6400,7 @@ void RayGen()
// the eventual swap-chain/backbuffer is LDR.
finalColor += emissiveSurface + emissiveBloom;
gOutputTex[pixel] = float4(PreparePathTraceOutputColor(finalColor), primaryHitDistance);
gOutputTex[pixel] = float4(PreparePathTraceOutputColor(finalColor) * outputAo, primaryHitDistance);
}
)";
@@ -6354,6 +6433,10 @@ cbuffer LightingCB : register(b0)
uint gSecondaryCorrectionBudget;
float gSecondaryLightCompensation;
uint gHistoryReset;
uint gExternalDenoiser;
float gGiAmount;
float gWorldGrimeAmount;
uint gPadding2;
};
Texture2D<float4> gAlbedoTex : register(t1);
@@ -6640,6 +6723,10 @@ cbuffer LightingCB : register(b0)
uint gSecondaryCorrectionBudget;
float gSecondaryLightCompensation;
uint gHistoryReset;
uint gExternalDenoiser;
float gGiAmount;
float gWorldGrimeAmount;
uint gPadding2;
};
Texture2D<float4> gAlbedoTex : register(t1);
@@ -8059,6 +8146,7 @@ static bool glRaytracingLightingExecuteInternal(
g_glRaytracingLighting.constants.screenSize[2] = 1.0f / (float)pass->width;
g_glRaytracingLighting.constants.screenSize[3] = 1.0f / (float)pass->height;
g_glRaytracingLighting.constants.frameIndex = g_glRaytracingLighting.frameCounter;
g_glRaytracingLighting.constants.externalDenoiser = g_glRaytracingLighting.externalDenoiser ? 1u : 0u;
g_glRaytracingLighting.constants.lightCount =
(uint32_t)glRaytracingClamp<size_t>(g_glRaytracingLighting.cpuLights.size(), 0, GL_RAYTRACING_MAX_LIGHTS);
@@ -8424,6 +8512,9 @@ bool glRaytracingLightingInit(void)
g_glRaytracingLighting.constants.secondaryCorrectionBudget = 0;
g_glRaytracingLighting.constants.secondaryLightCompensation = 0.62f;
g_glRaytracingLighting.constants.historyReset = 1u;
g_glRaytracingLighting.constants.externalDenoiser = 0u;
g_glRaytracingLighting.constants.giAmount = 1.0f;
g_glRaytracingLighting.constants.worldGrimeAmount = 0.35f;
glRaytracingLightingResetDenoiseHistory();
glRaytracingLightingUpdateConstants();
@@ -8653,6 +8744,30 @@ void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_
glRaytracingLightingUpdateConstants();
}
void glRaytracingLightingSetGIAmount(float amount)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
amount = glRaytracingClamp<float>(amount, 0.0f, 8.0f);
if (g_glRaytracingLighting.constants.giAmount != amount)
glRaytracingLightingResetDenoiseHistory();
g_glRaytracingLighting.constants.giAmount = amount;
glRaytracingLightingUpdateConstants();
}
void glRaytracingLightingSetWorldGrime(float amount)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
amount = glRaytracingClamp<float>(amount, 0.0f, 4.0f);
if (g_glRaytracingLighting.constants.worldGrimeAmount != amount)
glRaytracingLightingResetDenoiseHistory();
g_glRaytracingLighting.constants.worldGrimeAmount = amount;
glRaytracingLightingUpdateConstants();
}
void glRaytracingLightingSetSecondaryLightBudget(int budget, float compensation)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
@@ -8717,6 +8832,8 @@ void glRaytracingLightingSetExternalDenoiser(int enabled)
glRaytracingLightingResetDenoiseHistory();
g_glRaytracingLighting.externalDenoiser = newValue;
g_glRaytracingLighting.constants.externalDenoiser = newValue ? 1u : 0u;
glRaytracingLightingUpdateConstants();
}
void glRaytracingLightingUseExternalDenoiser(int enabled)