Skip to content

Conversation

Mugen87
Copy link
Collaborator

@Mugen87 Mugen87 commented Sep 7, 2025

Fixed #29668.

Description

The PR adds a new SSGI post processing node for WebGPURenderer. The implementation is based on https://github.com/cdrinmatane/SSRT3 which is a SSGI component for Unity.

SSGINode is a complete port of the Unity code and supports all features that were missing in the experimental versions in #29668. E.g. SSGINode supports temporal filtering, view-space sampling or the original noise data from the Unity source. The discussions and code from #29668 where a real help and time-saver so many thanks to all contributors!

The purpose of SSGI is to add indirect diffuse light and AO to a scene. Similar to other modern SSGI implementations, this one works best with temporal filtering which means it is used together with TAA. In that case, noise that is normally quite visible can be effectively reduced without a dedicated denoise() pass. Depending on whether temporal filtering is used or not, the effect should be configured a bit differently. I've added some comments for this in the JSDoc of the class.

The default settings of the node are relatively low so the effect runs with 60 FPS on a Pixel 8a and a macMini with a high resolution Studio Display screen. You will notice some temporal instabilities at certain surfaces with a slice count of one which can be mitigate by increasing it to two (like in the demo). The slice count has a huge performance impact though so you will see performance drops when ramping up the quality. It heavily depends on the scene what kind of settings are required so the result looks good. Another thing that you might notice is ghosting when moving the camera which is typical for temporal techniques. We might be able to reduce this by improving the TAA over time though. Keep in mind that SSGI is in general an expensive FX effect so it should be used in a sensible way.

Live demo: https://rawcdn.githack.com/mrdoob/three.js/dev/examples/webgpu_postprocessing_ssgi.html

@zalo
Copy link
Contributor

zalo commented Sep 7, 2025

Awesome! Looking good!

Since it’s using temporal accumulation, perhaps the noise pattern should be randomized every frame to even out the dithering pattern 😄

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 7, 2025

Interesting! Do you have a reference for how this is done?

We want to include temporal accumulation in other effects like SSR as well so information about this topic are highly welcome.

@Mugen87 Mugen87 added this to the r181 milestone Sep 7, 2025
@zalo
Copy link
Contributor

zalo commented Sep 7, 2025

Everywhere “frameNumber” is used here is for hacking in temporal jitter:
https://github.com/zalo/three.js/blob/2b2c012ed88d402e53c53c14823aff1295440367/examples/jsm/shaders/SSILVBShader.js#L90

The temporal jitter checkbox should enable it here:
https://raw.githack.com/zalo/three.js/feat-ssilvb-gtvbao/examples/webgl_postprocessing_ssilvb.html

I’m not 1,000,000% sure it will converge, but it might help 😅

I’d love to see a dropdown that switches between the no-SSGI color, the pure SSGI channel, and the composite!

@Maksims
Copy link

Maksims commented Sep 7, 2025

This looks cool.
But the demo is scene used is missleading, as it has lightmaps with baked GI in them.
To present the technique in its actual quality, it is best to use scene with dynamic lights and shadow maps, but without lightmaps.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 7, 2025

100% agreed!

I've just struggled to find a free, good looking glTF asset with an appropriate CC license and material/texture setup. Many assets at Sketchfab bake light and shadows directly into the diffuse textures so there is not even an option to remove the baked lighting which would be possible with separate light maps. I also wanted to avoid to reuse an existing asset in the repository so we can provide fresh visuals. Help in this context would be highly welcome. Maybe someone can recommend or even share an appropriate asset?

@zalo Thanks! Let's give this approach a go when the PR got merged.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 7, 2025

I’d love to see a dropdown that switches between the no-SSGI color, the pure SSGI channel, and the composite!

The last entry in the GUI named output should hopefully do what you are looking for. Beauty is the unprocessed beauty pass (so no-SSGI color), GI is the pure SSGI channel and Default is the composite. Or are you referring to something else?

@sunag
Copy link
Collaborator

sunag commented Sep 7, 2025

Congratulations @Mugen87 , quite amazing.

@hybridherbst
Copy link
Contributor

Looks very nice!

Would it be possible to also get a denoise pass in? Maybe the denoise pass from N8AO by @N8python would be suitable here? (https://github.com/N8python/n8ao/blob/master/src/N8AOPass.js#L433)

@zalo
Copy link
Contributor

zalo commented Sep 8, 2025

Or are you referring to something else?

Ah, nope! 😅 It was hidden on mobile until I scrolled down. 🫠

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 8, 2025

Would it be possible to also get a denoise pass in?

A denoise pass is already available as DenoiseNode.

/**
* Post processing node for denoising data like raw screen-space ambient occlusion output.
* Denoise can noticeably improve the quality of ambient occlusion but also add quite some
* overhead to the post processing setup. It's best to make its usage optional (e.g. via
* graphic settings).
*
* Reference: {@link https://openaccess.thecvf.com/content/WACV2021/papers/Khademi_Self-Supervised_Poisson-Gaussian_Denoising_WACV_2021_paper.pdf}.
*
* @augments TempNode
* @three_import import { denoise } from 'three/addons/tsl/display/DenoiseNode.js';
*/
class DenoiseNode extends TempNode {

The respective TSL function denoise() is documented here:

/**
* TSL function for creating a denoise effect.
*
* @tsl
* @function
* @param {Node} node - The node that represents the input of the effect (e.g. AO).
* @param {Node<float>} depthNode - A node that represents the scene's depth.
* @param {?Node<vec3>} normalNode - A node that represents the scene's normals.
* @param {Camera} camera - The camera the scene is rendered with.
* @returns {DenoiseNode}
*/
export const denoise = ( node, depthNode, normalNode, camera ) => nodeObject( new DenoiseNode( convertToTexture( node ), nodeObject( depthNode ), nodeObject( normalNode ), camera ) );

You would use denoise() right after the GI pass and then use the result for the composite:

const denoisePass = denoise( giPass, scenePassDepth, scenePassNormal, camera );

@Mugen87 Mugen87 merged commit 22e1b94 into mrdoob:dev Sep 8, 2025
8 checks passed
@zalo
Copy link
Contributor

zalo commented Sep 9, 2025

Hmm, @Mugen87 I think it might be too early to close #29668... I just found the time to sit down and test everything...

I think there may be some significant bugs in the SSGI implementation...

Here's the #29668 's (three.js GT-VBAO) implementation with 2 slices and 8 steps:
Image

And here's the WebGPU TSL SSGI Implementation with 2 slices and 8 steps:
Image

GT-VBAO 32 steps:
image

SSGI 32 steps:
image

The SSGI one seems to get exponentially worse as more steps are added... likewise, I don't think the temporal jitter is working as expected 💀
Perhaps it is worth adding some more intermediate debug views between the existing implementations and tracking down where they diverge 😅

I wish I could work with TSL as well as GLSL 🫠

@zalo
Copy link
Contributor

zalo commented Sep 9, 2025

Hm, the SSRT3 "three.js" implementation is here; which wasn't quite right to the Unity version either 😅
https://raw.githack.com/zalo/three.js/feat-ssilvb/examples/webgl_postprocessing_ssilvb.html
https://github.com/zalo/three.js/blob/01789a62f2abac47159c81ff9aa482441b519dfc/examples/jsm/shaders/SSILVBShader.js

Which implementation should I step through line by line to look for differences?

@hybridherbst
Copy link
Contributor

The implementation at https://raw.githack.com/zalo/three.js/feat-ssilvb/examples/webgl_postprocessing_ssilvb.html goes darker with higher AOSamples count, that is probably not intended, right?

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

@zalo I have used the code from https://github.com/cdrinmatane/SSRT3/tree/main/HDRP as a reference. When visually comparing SSGINode with your port, I have temporarily exchanged below code to match yours so the ray starts of the same (I've seen you have used the results of randf() in these lines):

const noiseOffset = spatialOffsets( screenCoordinate );
const noiseDirection = gradientNoise( screenCoordinate );
const initialRayStep = fract( noiseOffset.add( this._temporalOffset ) ).add( rand( uvNode ).mul( 2 ).sub( 1 ) );

But I did revert to the original version. The way you have computed the horizon did not seem plausible to me so I sticked to the original version as well.

Instead of reopening #29668, I would prefer to open a new issue focusing on SSGINode.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

@cdrintherrieno Hi there 👋 ! Glady to report that SSRT3 founds its way in the main repo but it seems there is an issue in our AO implementation that makes the AO too dark the more samples are used (see #31839 (comment)). I could not reproduce this issue own my side so maybe it you could have a look at our demos?

You can use below URLs for testing:

https://rawcdn.githack.com/Mugen87/three.js/88e013b60298ed85d6557f4f954a57692122ca4a/examples/webgpu_postprocessing_ssgi.html
https://rawcdn.githack.com/mrdoob/three.js/8683d9657d3d9b83e9055025c95edcff71281be9/examples/webgpu_postprocessing_ssgi.html

Does the AO/GI look plausible to you? You can visually debug the results of the AO/GI by changing the output in the GUI. When doing so, it's best to disable temporal filtering so you get stable frames.

BTW: The code of the implementation is here:

https://github.com/mrdoob/three.js/blob/dev/examples/jsm/tsl/display/SSGINode.js

The actual shader code is implemented in the setup() method.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

@zalo I have tested the other scene with SSGINode and I get a completely different result than in your post. It looks as expected to me:

image

Here is a link for testing using the latest code from dev, just with another scene setup in webgpu_postprocessing_ssgi:

https://rawcdn.githack.com/Mugen87/three.js/88e013b60298ed85d6557f4f954a57692122ca4a/examples/webgpu_postprocessing_ssgi.html

I also can't observe the mentioned darkening with higher step counts. Some areas are getting a more prominent AO, yes, but it does not look like in your second screenshot. It looks as expected to me.

@zalo
Copy link
Contributor

zalo commented Sep 9, 2025

Woah yeah that is completely different on my phone! I can see the OP’s example work correctly on my phone now… I’ll check to see what’s different about my code or how I called it in the morning in a few hours …. Perhaps 16-bit textures were getting used and messing up the bit counting?

In the new mostly correct version in the OP, I am noticing a leftward bias to the darkening (that goes away when you look at the scene from the top-down).

ScreenRecording_09-09-2025.06-22-09_1.mp4

This behavior does not appear in the new Little Tokyo demo you linked! 🧐

@cdrintherrieno
Copy link

cdrintherrieno commented Sep 9, 2025

@Mugen87 Very nice to see it implemented in ThreeJS! Indeed the AO seems wrong, also it flickers which indicates that the slice parametrization is not symmetric. If I had to guess based on a quick glance at the code, it's probably around these parts:

let frontBackHorizon = vec2( dot( pixelToSample, viewDir ), dot( pixelToSampleBackface, viewDir ) );
frontBackHorizon = GTAOFastAcos( clamp( frontBackHorizon, - 1, 1 ) );
frontBackHorizon = clamp( div( mul( samplingDirection, vec2( frontBackHorizon.x.negate(), frontBackHorizon.y ) ).sub( n.sub( HALF_PI ) ), PI ) ); // Port note: This line also required an update because of different uv conventions
frontBackHorizon = directionIsRight.equal( true ).select( frontBackHorizon.yx, frontBackHorizon.xy ); // Front/Back get inverted depending on angle

You can also compare with other implementations (although I'm not sure if they use the same coordinate system as WebGPU):
https://www.shadertoy.com/view/dsGBzW
https://www.shadertoy.com/view/XXGSDd
https://github.com/martymcmodding/iMMERSE/blob/main/Shaders/MartysMods_MXAO.fx#L592

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

I think there are two major differences in coordinate space conventions that a port must honor. In WebGPU, the uv (0,0) represents the top-left corner whereas in Unity it should be bottom-left. For matching uv offsets, three's implementation must compute the uv and sampling directions differently.

const uvDirection = directionIsRight.equal( true ).select( vec2( 1, - 1 ), vec2( - 1, 1 ) ); // Port note: Because of different uv conventions, uv-y has a different sign
const samplingDirection = directionIsRight.equal( true ).select( 1, - 1 );

I believe this bit is correct. What I'm unsure about is the second difference in view space handedness. In WebGPU and WebGL, the camera looks down the negative Z-axis by default so (0,0,-1). In Unity, it should be (0,0,1) (is that right?). So our viewZ values are also negative. That's why I had to add a negate() here to fix view space sampling.

stepRadius.assign( max( RADIUS.mul( this._halfProjScale ).div( viewPosition.z.negate() ), float( STEP_COUNT ) ) ); // Port note: viewZ is negative so a negate is requried

This difference in view space handedness could also affect the slice parametrization. Ideally, we don't get it right by trial and error but can understand the math differences in the shader. Can you think of a part of the frontBackHorizon computation that needs an update if the view space handedness is inverted?

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

Found one bug which is fixed via #31863. Keep working on potential horizon issue...

@Mirko-Salm
Copy link

I'm genuinely curious what made you decide to go with SSGI instead of GT-VBGI (https://www.shadertoy.com/view/lfdBWn). Since you already have a functional GT-VBAO implementation, getting GT-VBGI to work should have been straightforward.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

TBH, I'm new to SSGI and I found the SSRT3 solution well documented. And since I have worked with Unity a bit, it was easier to study and port the code.

Do you mind explaining the differences between SSRT3 and GT-VBGI? From the comparison screenshots in #29668, I could not tell whether GT-VBAO or SSRT3 produces the better AO.

To be clear, the current implementation in SSGINode is a first step so we have something in the main repository to work with. There is no reason why we should not switch to a different and better implementation. A working SSRT3 version makes it also easier to switch to a different technique since we have some sort of baseline for comparisons.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

@zalo I have verified the code one more time and I think the formulas are now correctly ported to the coordinate space conventions of WebGPU and WebGPURenderer. The only thing I am not fully confident is the - n + HALF_PI part which produces completely broken results if I port it 1:1. There is a sign flip needed to accommodate the difference in the coordinates systems. It would be great if you could port this somehow to your pure GLSL version and check the result. If you feel the AO is not correct, we should find out if it's a general problem of SSRT3 or if our ports have open issues.

@zalo
Copy link
Contributor

zalo commented Sep 9, 2025

I'm genuinely curious what made you decide to go with SSGI instead of GT-VBGI (https://www.shadertoy.com/view/lfdBWn). Since you already have a functional GT-VBAO implementation, getting GT-VBGI to work should have been straightforward.

For myself I think GT-VBAO/GI looks a lot better, but it was significantly more complicated to port from Shadertoy… When it came time to port the port I had to TSL (the JavaScript method chaining shader language that new three.js shaders use) I found I couldn’t get over the threshold in the spare time I had…

I had Claude Code attempt it again yesterday, but something else mysterious was broken on my machine, so it was all doomed to fail…

The only thing I am not fully confident is the - n + HALF_PI part which produces completely broken results if I port it 1:1. There is a sign flip needed to accommodate the difference in the coordinates systems.

Usually this means something else is flipped earlier in the pipeline 🧐
Might fire up Unity and take a look soon

@Mirko-Salm
Copy link

The differences are basically the same as those outlined in the GT-VBAO docu here: https://www.shadertoy.com/view/XXGSDd.
The biggest selling point of GT-VBAO/GI might be that it converges to the same results that a brute-force screen-space ray-marcher converges to (as demonstrated by all the GT-VBAO/GI shadertoy implementations). If you prefer the look of uniformly-weighted sampling over cosine-weighted sampling there are also uniformly-weighted variants of GT-VBAO/GI. Those might actually be a bit faster since they don't require acos calls inside the inner loop. Recently I also added distant light sampling support to (cosine-weighted) GT-VBAO: https://www.shadertoy.com/view/wc2SzR.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

Okay, I'll check out GT-VBAO next when I'm happy with the SSRT3 code. In the meanwhile, I would appreciate any help in evaluating our port of SSRT3 so we know the coordinate space sensitive operations are correct. This will also help us when writing the TSL for GT-VBGI. BTW: I would prefer to do this manually and not with an AI so we can evaluate, understand and document (if necessary) each line.

@zalo Thank you for your help here ❤️ ! I'm convinced any three.js SSGI and AO implementation will benefit if we get our SSRT3 right. We can document all relevant port changes so it's clear for developers what parts of the reference code have been updated in what way.

@zalo
Copy link
Contributor

zalo commented Sep 9, 2025

Ahh, so the source of the major discrepancy was that it was falling back to WebGL when I did local development without https (and I guess in other weird contexts); it seems like there's something in here that breaks when emitting GLSL. When forced to https, it uses WebGPU and everything looks as expected.

Secondly, I think I found the AO bug! When I change the PI on this line to PI2, everything looks beautiful and non-flickery:

const rotationAngle = mul( float( i ).add( noiseDirection ).add( this._temporalDirection ), PI.div( float( ROTATION_COUNT ) ) ).toConst();

I'm not sure why, since that correlates with this line which still has it as PI:
https://github.com/cdrinmatane/SSRT3/blob/main/HDRP/Shaders/Resources/SSRTCS.compute#L348

Sorry for the compression making it rough...

Recording.2025-09-09.123545.mp4

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

Secondly, I think I found the AO bug! When I change the PI on this line to PI2, everything looks beautiful and non-flickery:

Indeed, that's it! Awesome! Would you like to make a PR with the fix?

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 9, 2025

Ahh, so the source of the major discrepancy was that it was falling back to WebGL when I did local development without https

Makes sense! Indeed, there is an issue on the GLSL side. In some areas, the AO looks darker than in the WGSL version. I'll have a look at this tomorrow unless you find the root cause ahead of me^^.

@zalo
Copy link
Contributor

zalo commented Sep 9, 2025

Comparing the "fixed" SSGI (SSRT3) shader with the three.js GT-VBAO:

Recording.2025-09-09.162623.mp4

While the SSRT3 SSGI is certainly an improvement on GTAO, I think GT-VBAO/GI (maybe with distant light sampling?) will be a significant quality improvement even on top of that, if we can work it.

Also, this is all raising the necessity for marking pixels "dirty" in the TRAA pass, to prevent ghosting...

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 10, 2025

#31873 fixed a bug in SSGINode that substantially compromised the bitfield. This bug was the actual root cause for the AO flickering and was also responsible for the mentioned quality issues.

The new version produces a noticeably better AO. I guess we need a new comparison video for #31839 (comment) ^^.

@zalo
Copy link
Contributor

zalo commented Sep 10, 2025

Here's the latest comparison between the two implementations, both set to 4 slices and 32 samples (other settings adjusted to be similar style):
SSGIvsSSILVB

The smoother/nicer one is the fixed SSGI 😄 I no longer think that the incremental improvement from GT-VBAO will make a huge difference...

Now there are just a couple smearing issues with the TRAA to solve... and I might commit some extra changes to the scene. The "Neutral Tonemapping" and Exposure set to 1.5 is crushing out a lot of the detail, and the "pre-baked" lighting room is hiding a lot of the benefit 😄

@zalo
Copy link
Contributor

zalo commented Sep 10, 2025

As far as the demo scene goes... the current room is a crime compared to some of these other models

Spaceship Hallway shows off both the AO and the GI really well, since it has no baked in lighting (this is JUST the SSGI postprocess):
SSGIComparison

EDIT: This scene does not look nearly as good when the GI compositing is fixed. Guess it was just lucky.

I'll look into making a custom demo scene to show it off in a few hours...

@zalo
Copy link
Contributor

zalo commented Sep 11, 2025

Hmm, there's another issue... it looks like the GI doesn't act like normal light, it just adds itself on top of the scene.
SponzaLightBug

SponzaLightBug2

Since the Albedo/Normals/Roughness/etc. GBuffers are present, would it make sense to interpret the GI as PBR light when compositing?

At the very least, it should account for the underlying color/textures somehow...

@zalo
Copy link
Contributor

zalo commented Sep 11, 2025

Aha, I've got a fix

Just need to swap out:

const compositePass = vec4( add( scenePassColor.rgb, gi ).mul( ao ), scenePassColor.a );

for:

const compositePass = vec4( scenePassColor.rgb.mul( ao ).add( scenePassDiffuse.rgb.mul(gi)), scenePassColor.a );

SponzaLightBugFix

I'll make a PR for it.

@zalo
Copy link
Contributor

zalo commented Sep 11, 2025

Considering a Cornell Box since it very succinctly shows the benefits of AO+GI and it looks nice with the settings dialed in:
CornellBoxComparison2

(Here's the lit frame at full color depth)
image

Cornell Box Scene Code
// Walls
let geo = new THREE.PlaneGeometry(1, 1);
let mat = new THREE.MeshPhysicalMaterial({ color: "#ff0000" });
let mesh = new THREE.Mesh(geo, mat);
mesh.scale.set( 20, 15, 1 );
mesh.rotation.y = Math.PI * 0.5;
mesh.position.set(-10, 7.5, 0);
mesh.receiveShadow = true;
scene.add(mesh);

mat = new THREE.MeshPhysicalMaterial({ color: "#00ff00" });
mesh = new THREE.Mesh(geo, mat);
mesh.scale.set( 20, 15, 1 );
mesh.rotation.y = Math.PI * -0.5;
mesh.position.set(10, 7.5, 0);
mesh.receiveShadow = true;
scene.add(mesh);

mat = new THREE.MeshPhysicalMaterial({ color: "#fff" });
mesh = new THREE.Mesh(geo, mat);
mesh.scale.set( 20, 20, 1 );
mesh.rotation.x = Math.PI * -.5;
mesh.receiveShadow = true;
scene.add(mesh);

mesh = new THREE.Mesh(geo, mat);
mesh.scale.set( 15, 20, 1 );
mesh.rotation.z = Math.PI * -0.5;
mesh.position.set(0, 7.5, -10);
mesh.receiveShadow = true;
scene.add(mesh);

mesh = new THREE.Mesh(geo, mat);
mesh.scale.set( 20, 20, 1 );
mesh.rotation.x = Math.PI * 0.5;
mesh.position.set(0, 15, 0);
mesh.receiveShadow = true;
scene.add(mesh);

// Tall Box
geo = new THREE.BoxGeometry(5, 7, 5);
mesh = new THREE.Mesh(geo, mat);
mesh.rotation.y = Math.PI * 0.25;
mesh.position.set(-3, 3.5, -2);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);

// Short Box
geo = new THREE.BoxGeometry(4, 4, 4);
mesh = new THREE.Mesh(geo, mat);
mesh.rotation.y = Math.PI * -0.1;
mesh.position.set(4, 2, 4);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);

// Lampshade
mesh = new THREE.Mesh(new THREE.CylinderGeometry(2.5, 2.5, 1, 64), 
					  new THREE.MeshBasicMaterial());
mesh.position.y = 15;
scene.add(mesh);

// Main Light
let light = new THREE.PointLight("#ffffff", 100);
light.position.set(0, 13, 0);
light.distance = 100;
light.castShadow = true;
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;
light.shadow.bias = -0.002;
scene.add(light);

// Ambient Light
light = new THREE.AmbientLight("#0c0c0c");
scene.add(light);

Also, it seems like there's another bug where the screen space number of steps decreases the effective radius because the step radius is getting divided by the number of steps twice; I put a fix for that into my PR as well.

@zalo
Copy link
Contributor

zalo commented Sep 12, 2025

I've got an improvement to the temporal noise coming down the pipe in #31890

And I took a stab at trying to fix the ghosting in the TRAA implementation, but persisting the previous frame's depth to the next frame was too much for me, so I made an issue at #31892

Lastly, I have this Cornell Box SSGI Example Scene, does this seem good? Should I make a PR for this?

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Sep 12, 2025

Lastly, I have this Cornell Box SSGI Example Scene, does this seem good? Should I make a PR for this?

That would be great!

@zalo
Copy link
Contributor

zalo commented Sep 13, 2025

Unless we want to do a two part TRAA or have the SSGI take in Roughness/Specular to subsume SSR, then I think I'm done for this release. 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Postprocessing: Add SSILVB GI and AO
7 participants