Skip to content

Commit 36e16ee

Browse files
committed
feat(vulkan): activate gi post resolve execution path
1 parent b726c85 commit 36e16ee

6 files changed

Lines changed: 57 additions & 7 deletions

File tree

engine-impl-vulkan/src/main/java/org/dynamislight/impl/vulkan/capability/VulkanGiCapabilityDescriptorV2.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -309,17 +309,37 @@ float giHash12(vec2 p) {
309309
return fract((p3.x + p3.y) * p3.z);
310310
}
311311
vec4 resolveGiIndirect(vec4 baseColor, vec2 uv) {
312+
vec2 texel = 1.0 / vec2(textureSize(uSceneColor, 0));
313+
vec3 c0 = texture(uSceneColor, uv).rgb;
314+
vec3 c1 = texture(uSceneColor, clamp(uv + vec2(texel.x, 0.0), vec2(0.0), vec2(1.0))).rgb;
315+
vec3 c2 = texture(uSceneColor, clamp(uv - vec2(texel.x, 0.0), vec2(0.0), vec2(1.0))).rgb;
316+
vec3 c3 = texture(uSceneColor, clamp(uv + vec2(0.0, texel.y), vec2(0.0), vec2(1.0))).rgb;
317+
vec3 c4 = texture(uSceneColor, clamp(uv - vec2(0.0, texel.y), vec2(0.0), vec2(1.0))).rgb;
318+
vec3 probeInterp = (c0 * 0.40) + ((c1 + c2 + c3 + c4) * 0.15);
312319
float probeBand = smoothstep(0.15, 0.85, giHash12(uv * 64.0));
313-
float probeContribution = mix(0.06, 0.16, probeBand);
314-
vec3 lifted = baseColor.rgb * (1.0 + probeContribution);
320+
float probeContribution = mix(0.05, 0.14, probeBand);
321+
vec3 lifted = mix(baseColor.rgb, probeInterp, 0.18 + probeContribution);
315322
return vec4(clamp(lifted, vec3(0.0), vec3(1.0)), baseColor.a);
316323
}
317324
""";
318325
case "rtgi_single" -> """
319326
vec4 resolveGiIndirect(vec4 baseColor, vec2 uv) {
327+
vec2 texel = 1.0 / vec2(textureSize(uSceneColor, 0));
328+
vec2 ray = normalize((uv - vec2(0.5)) + vec2(0.0001));
329+
vec3 rtAccum = vec3(0.0);
330+
float rtWeight = 0.0;
331+
for (int i = 0; i < 8; i++) {
332+
float t = (float(i) + 1.0) / 8.0;
333+
vec2 sampleUv = clamp(uv + ray * texel * (3.0 + t * 14.0), vec2(0.0), vec2(1.0));
334+
vec3 c = textureLod(uSceneColor, sampleUv, 0.6 + t * 1.4).rgb;
335+
float w = 1.0 - (t * 0.65);
336+
rtAccum += c * w;
337+
rtWeight += w;
338+
}
339+
vec3 rtColor = rtWeight > 0.0001 ? rtAccum / rtWeight : baseColor.rgb;
320340
float centerWeight = 1.0 - clamp(length((uv - vec2(0.5)) * 1.6), 0.0, 1.0);
321-
float rtContribution = mix(0.08, 0.20, centerWeight);
322-
vec3 lifted = baseColor.rgb * (1.0 + rtContribution);
341+
float rtContribution = mix(0.08, 0.18, centerWeight);
342+
vec3 lifted = mix(baseColor.rgb, rtColor, 0.18 + rtContribution * 0.35);
323343
return vec4(clamp(lifted, vec3(0.0), vec3(1.0)), baseColor.a);
324344
}
325345
""";
@@ -330,21 +350,36 @@ float giHash12(vec2 p) {
330350
return fract((p3.x + p3.y) * p3.z);
331351
}
332352
vec4 resolveGiIndirect(vec4 baseColor, vec2 uv) {
353+
vec2 texel = 1.0 / vec2(textureSize(uSceneColor, 0));
354+
vec3 center = texture(uSceneColor, uv).rgb;
355+
vec3 neighX = texture(uSceneColor, clamp(uv + vec2(texel.x, 0.0), vec2(0.0), vec2(1.0))).rgb;
356+
vec3 neighY = texture(uSceneColor, clamp(uv + vec2(0.0, texel.y), vec2(0.0), vec2(1.0))).rgb;
357+
vec3 ssgiInterp = (center * 0.55) + ((neighX + neighY) * 0.225);
358+
vec2 ray = normalize((uv - vec2(0.5)) + vec2(0.0001));
359+
vec3 rtTap = textureLod(uSceneColor, clamp(uv + ray * texel * 9.0, vec2(0.0), vec2(1.0)), 1.2).rgb;
333360
float probeBand = smoothstep(0.10, 0.90, giHash12(uv * 48.0));
334361
float centerWeight = 1.0 - clamp(length((uv - vec2(0.5)) * 1.5), 0.0, 1.0);
335362
float ssgiContribution = 0.07;
336363
float probeContribution = mix(0.04, 0.10, probeBand);
337364
float rtContribution = mix(0.03, 0.09, centerWeight);
338365
float hybridContribution = ssgiContribution + probeContribution + rtContribution;
339-
vec3 lifted = baseColor.rgb * (1.0 + hybridContribution);
366+
vec3 hybrid = mix(ssgiInterp, rtTap, 0.35 + rtContribution);
367+
vec3 lifted = mix(baseColor.rgb, hybrid, 0.20 + hybridContribution * 0.45);
340368
return vec4(clamp(lifted, vec3(0.0), vec3(1.0)), baseColor.a);
341369
}
342370
""";
343371
default -> """
344372
vec4 resolveGiIndirect(vec4 baseColor, vec2 uv) {
373+
vec2 texel = 1.0 / vec2(textureSize(uSceneColor, 0));
374+
vec3 c = texture(uSceneColor, uv).rgb;
375+
vec3 cx = texture(uSceneColor, clamp(uv + vec2(texel.x, 0.0), vec2(0.0), vec2(1.0))).rgb;
376+
vec3 cy = texture(uSceneColor, clamp(uv + vec2(0.0, texel.y), vec2(0.0), vec2(1.0))).rgb;
377+
float depth = texture(uVelocityColor, uv).b;
345378
float horizon = clamp(1.0 - abs(uv.y - 0.5) * 2.0, 0.0, 1.0);
346-
float ssgiContribution = mix(0.05, 0.14, horizon);
347-
vec3 lifted = baseColor.rgb * (1.0 + ssgiContribution);
379+
float depthAtten = clamp(1.0 - depth * 0.65, 0.15, 1.0);
380+
float ssgiContribution = mix(0.05, 0.14, horizon) * depthAtten;
381+
vec3 ssgiColor = (c * 0.6) + ((cx + cy) * 0.2);
382+
vec3 lifted = mix(baseColor.rgb, ssgiColor, 0.16 + ssgiContribution * 0.50);
348383
return vec4(clamp(lifted, vec3(0.0), vec3(1.0)), baseColor.a);
349384
}
350385
""";

engine-impl-vulkan/src/main/java/org/dynamislight/impl/vulkan/shader/VulkanPostShaderSources.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,9 @@ void main() {
469469
centerMaterialReactive,
470470
reflectionDisocclusionSignal
471471
);
472+
vec4 giResolved = resolveGiIndirect(vec4(clamp(color, 0.0, 1.0), historyConfidenceOut), vUv);
473+
color = giResolved.rgb;
474+
historyConfidenceOut = clamp(max(historyConfidenceOut, giResolved.a), 0.0, 1.0);
472475
outColor = vec4(clamp(color, 0.0, 1.0), historyConfidenceOut);
473476
}
474477
""";

engine-impl-vulkan/src/main/java/org/dynamislight/impl/vulkan/shader/VulkanShaderSources.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.List;
44
import org.dynamislight.impl.vulkan.capability.VulkanAaCapabilityDescriptorV2;
5+
import org.dynamislight.impl.vulkan.capability.VulkanGiCapabilityDescriptorV2;
56
import org.dynamislight.impl.vulkan.capability.VulkanReflectionCapabilityDescriptorV2;
67
import org.dynamislight.impl.vulkan.capability.VulkanShadowCapabilityDescriptorV2;
78
import org.dynamislight.spi.render.RenderShaderModuleDeclaration;
@@ -88,6 +89,8 @@ private static List<RenderShaderModuleDeclaration> runtimePostModules() {
8889
.shaderModules(VulkanReflectionCapabilityDescriptorV2.MODE_HYBRID));
8990
modules.addAll(VulkanAaCapabilityDescriptorV2.withMode(VulkanAaCapabilityDescriptorV2.MODE_TAA)
9091
.shaderModules(VulkanAaCapabilityDescriptorV2.MODE_TAA));
92+
modules.addAll(VulkanGiCapabilityDescriptorV2.withMode(VulkanGiCapabilityDescriptorV2.MODE_SSGI)
93+
.shaderModules(VulkanGiCapabilityDescriptorV2.MODE_SSGI));
9194
return List.copyOf(modules);
9295
}
9396
}

engine-impl-vulkan/src/test/java/org/dynamislight/impl/vulkan/shader/VulkanShaderPhaseCParallelValidationTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.Set;
1010
import java.util.stream.Stream;
1111
import org.dynamislight.impl.vulkan.capability.VulkanAaCapabilityDescriptorV2;
12+
import org.dynamislight.impl.vulkan.capability.VulkanGiCapabilityDescriptorV2;
1213
import org.dynamislight.impl.vulkan.capability.VulkanReflectionCapabilityDescriptorV2;
1314
import org.dynamislight.impl.vulkan.capability.VulkanShadowCapabilityDescriptorV2;
1415
import org.dynamislight.spi.render.RenderFeatureMode;
@@ -65,10 +66,14 @@ private static List<RenderShaderModuleDeclaration> gatherModules(
6566
VulkanReflectionCapabilityDescriptorV2.withMode(reflectionMode).shaderModules(reflectionMode);
6667
List<RenderShaderModuleDeclaration> aaModules =
6768
VulkanAaCapabilityDescriptorV2.withMode(aaMode).shaderModules(aaMode);
69+
List<RenderShaderModuleDeclaration> giModules =
70+
VulkanGiCapabilityDescriptorV2.withMode(VulkanGiCapabilityDescriptorV2.MODE_SSGI)
71+
.shaderModules(VulkanGiCapabilityDescriptorV2.MODE_SSGI);
6872
java.util.ArrayList<RenderShaderModuleDeclaration> all = new java.util.ArrayList<>();
6973
all.addAll(shadowModules);
7074
all.addAll(reflectionModules);
7175
all.addAll(aaModules);
76+
all.addAll(giModules);
7277
return List.copyOf(all);
7378
}
7479

engine-impl-vulkan/src/test/java/org/dynamislight/impl/vulkan/shader/VulkanShaderSourcesTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,8 @@ void postFragmentIncludesReflectionOverrideModes() {
112112
assertTrue(shader.contains("bool transparentCandidate = materialReactive >= 0.30;"));
113113
assertTrue(shader.contains("if (probeOnlyOverride) {"));
114114
assertTrue(shader.contains("int mode = reflectionOverrideMode == 2 ? 1 : (packedMode & 7);"));
115+
assertTrue(shader.contains("vec4 resolveGiIndirect(vec4 baseColor, vec2 uv)"));
116+
assertTrue(shader.contains("vec4 giResolved = resolveGiIndirect(vec4(clamp(color, 0.0, 1.0), historyConfidenceOut), vUv);"));
117+
assertTrue(shader.contains("historyConfidenceOut = clamp(max(historyConfidenceOut, giResolved.a), 0.0, 1.0);"));
115118
}
116119
}

wish_list.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ GI notes:
220220
- GI phase-2A now has dedicated lockdown replay (`scripts/gi_phase2_ssgi_lockdown.sh`) and integration coverage for SSGI tier-default vs backend-override envelope/promotion thresholds.
221221
- GI phase-2A SSGI lockdown is now wired into CI as `gi-phase2-ssgi-lockdown` (plus workflow-dispatch toggle `run_gi_phase2_ssgi_lockdown`).
222222
- GI phase-2A now includes GI shader-module realization in composition (`resolveGiIndirect`) with mode-specific module declarations + descriptor-aligned bindings for `ssgi`, `probe_grid`, `rtgi_single`, and `hybrid_probe_ssgi_rt`.
223+
- GI post-composite execution now applies `resolveGiIndirect` in-frame after reflections, with mode-specific spatial sampling (SSGI neighborhood/depth attenuation, probe-grid interpolation, RT-detail ray taps, hybrid blend) using live scene inputs.
223224
- GI runtime now emits probe-grid policy/envelope/promotion telemetry (`GI_PROBE_GRID_POLICY_ACTIVE`, `GI_PROBE_GRID_ENVELOPE`, `GI_PROBE_GRID_ENVELOPE_BREACH`, `GI_PROBE_GRID_PROMOTION_READY`) with tier-default/override thresholds.
224225
- Typed GI promotion diagnostics now expose probe-grid expected/active ratio, cooldown/streak envelope state, and probe-grid promotion readiness for parser-free CI assertions.
225226
- GI runtime now emits probe-grid streaming/update cadence telemetry (`GI_PROBE_GRID_STREAMING_POLICY_ACTIVE`, `GI_PROBE_GRID_STREAMING_ENVELOPE`, `GI_PROBE_GRID_STREAMING_ENVELOPE_BREACH`) with configurable coverage/streak/cooldown thresholds and typed diagnostics fields (`probeGridConfiguredCount`, `probeGridActiveCount`, `probeGridUpdateBudgetPerFrame`, `probeGridUpdatesLastFrame`, `probeGridUpdateCoverageRatio`).

0 commit comments

Comments
 (0)