-
-
Notifications
You must be signed in to change notification settings - Fork 4k
bevy_solari: RIS for Direct Lighting #19620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bevy_solari: RIS for Direct Lighting #19620
Conversation
It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note. Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes. |
}, | ||
}; | ||
use camera_controller::{CameraController, CameraControllerPlugin}; | ||
use std::f32::consts::PI; | ||
|
||
/// `bevy_solari` demo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would really appreciate comments on exactly what users need to call to test this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's intended that you just run cargo run --example solari --features bevy_solari
, like any other example (it will warn you if you're missing the feature).
The extra options are meant more for me to use for development, and less for users to test.
@@ -0,0 +1,117 @@ | |||
#import bevy_core_pipeline::tonemapping::tonemapping_luminance as luminance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want a full approval from me, I'm going to need a bit of a comment-based walkthrough of each of the steps that we're taking inside of this shader. I understand the conceptual approach of restir, but I'm having trouble mapping it to this code because of my shader noobiness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
initial_and_temporal:
- Load a bunch of data about the current pixel (depth, normal, albedo, etc)
- Call generate_initial_reservoir() to get a reservoir (see the ReSTIR paper/course)
- Create an empty reservoir
- 32 times:
- Generate a random point on a light source (light sample)
- Calculate a resampling weight for that sample, based on the brightness of the light (without tracing any rays to test visibility)
- Add it to the reservoir
- After keeping the best of the 32 samples, trace a ray to test visibility
- Write the reservoir to a buffer
spatial_and_shade:
- Load the same pixel data again
- Grab the reservoir from the buffer
- Calculate the light contribution again
- Shade the current pixel (emissive + (radiance * reservoir weight * brdf * view exposure)).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually these steps will be expanded to reuse reservoirs temporally and spatially for better quality, but I'll leave that to the next PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a novice to this topic, I feel like it could benefit a lot from additional documentation.
I definitely don't expect to understand everything, but I think it would be easier to review and spot potential errors with some more explanations :)
let gpixel = textureLoad(gbuffer, global_id.xy, 0); | ||
let world_position = reconstruct_world_position(global_id.xy, depth); | ||
let world_normal = octahedral_decode(unpack_24bit_normal(gpixel.a)); | ||
let base_color = pow(unpack4x8unorm(gpixel.r).rgb, vec3(2.2)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, the 2.2 sounds oddly specific and is used twice in this shader, maybe it justifies a comment?
Or is it an "obvious" value if you know the technique?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not too sure what it's doing, but this code is copied from pbr_input_from_deferred_gbuffer
. It's unpacking the gbuffer data, which is in a compressed format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pow 2.2 is fake gamma correction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(this should ideally be an implementation detail of the gbuffer, and access done through a function)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am content enough with the code and docs quality here, and have a basic understanding of the rendering algorithm in play :) I also feel strongly that this is the right direction.
That said, please don't merge this without at least one rendering expert review.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good just some minor feedback. Exciting!
|
||
let size = (view_size.x * view_size.y) as u64 * RESERVOIR_STRUCT_SIZE; | ||
|
||
let reservoirs_a = render_device.create_buffer(&BufferDescriptor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really need new buffers every frame? Or could you cache the descriptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It already is cached :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yup, glazed right past that!
solari_lighting.as_deref().unwrap().clone(), | ||
SkipDeferredLighting, | ||
)); | ||
solari_lighting.as_mut().unwrap().reset = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't feel super strongly about this since we all know these patterns are hard to express but might be cleaner with a First
system that sets it to false each frame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ehh this is already what I did for taa. I'd rather keep it consistent.
# Objective - Start the realtime direct lighting work for bevy solari ## Solution - Setup all the CPU-side code for the realtime lighting path (minus some parts for the temporal reuse I haven't written yet) - Implement RIS with 32 samples to choose a good random light - Don't sample a disk for the directional light, just treat it as a single point. This is faster and not much worse quality. ## Future - Spatiotemporal reuse (ReSTIR DI) - Denoiser (DLSS-RR) - Light tile optimization for faster light selection - Indirect lighting (ReSTIR GI) ## Testing - Run the solari example to see realtime - Run the solari example with `-- --pathtracer` to see the existing pathtracer --- ## Showcase 1 frame direct lighting:  Accumulated pathtracer output:  --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Objective
Solution
Future
Testing
-- --pathtracer
to see the existing pathtracerShowcase
1 frame direct lighting:

Accumulated pathtracer output:
