Skip to content

Solari specular scene/PT support #20242

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

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open

Conversation

JMS55
Copy link
Contributor

@JMS55 JMS55 commented Jul 22, 2025

  • Adds roughness, metallic, and reflectance properties to solari's material system
  • Always calculate and expose world_tangent in ResolvedRayHitFull
  • Add brdf.wgsl with mixed diffuse/specular BRDF
  • Add GGX VNDF importance sampling functions to sampling.wgsl
  • Rewrite the pathtracer to use the specular BRDF
  • MIS for NEE/BRDF sampling implemented in the pathtracer thanks to @SparkyPotato

Note that specular support for the realtime lighting plugin will come at a future date. I think I want to focus on getting GI more stable and hooking up a denoiser first. This is just support for the material properties in RaytracingScenePlugin, and specular lighting in the PathtracingPlugin.

image

@JMS55 JMS55 added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen labels Jul 22, 2025
@JMS55 JMS55 requested a review from atlv24 July 22, 2025 04:12
@JMS55 JMS55 added this to the 0.17 milestone Jul 22, 2025
Comment on lines 30 to 68
// https://gpuopen.com/download/Bounded_VNDF_Sampling_for_Smith-GGX_Reflections.pdf (Listing 1)
fn sample_ggx_vndf(wi_tangent: vec3<f32>, roughness: f32, rng: ptr<function, u32>) -> vec3<f32> {
let i = wi_tangent;
let rand = rand_vec2f(rng);
let i_std = normalize(vec3(i.xy * roughness, i.z));
let phi = 2.0 * PI * rand.x;
let a = roughness;
let s = 1.0 + length(vec2(i.xy));
let a2 = a * a;
let s2 = s * s;
let k = (1.0 - a2) * s2 / (s2 + a2 * i.z * i.z);
let b = select(i_std.z, k * i_std.z, i.z > 0.0);
let z = fma(1.0 - rand.y, 1.0 + b, -b);
let sin_theta = sqrt(saturate(1.0 - z * z));
let o_std = vec3(sin_theta * cos(phi), sin_theta * sin(phi), z);
let m_std = i_std + o_std;
let m = normalize(vec3(m_std.xy * roughness, m_std.z));
return 2.0 * dot(i, m) * m - i;
}

// https://gpuopen.com/download/Bounded_VNDF_Sampling_for_Smith-GGX_Reflections.pdf (Listing 2)
fn ggx_vndf_pdf(wi_tangent: vec3<f32>, wo_tangent: vec3<f32>, roughness: f32) -> f32 {
let i = wi_tangent;
let o = wo_tangent;
let m = normalize(i + o);
let ndf = D_GGX(roughness, saturate(m.z));
let ai = roughness * i.xy;
let len2 = dot(ai, ai);
let t = sqrt(len2 + i.z * i.z);
if i.z >= 0.0 {
let a = roughness;
let s = 1.0 + length(i.xy);
let a2 = a * a;
let s2 = s * s;
let k = (1.0 - a2) * s2 / (s2 + a2 * i.z * i.z);
return ndf / (2.0 * (k * i.z + t));
}
return ndf * (t - i.z) / (2.0 * len2);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Jasmine's version is less code, I wonder why the big difference and whether i could just use this function in my case as is. I'll test it out and share my findings.

@mate-h
Copy link
Contributor

mate-h commented Jul 22, 2025

I tried this out, started going through the code, and looks very good at a first glance.
Leaving this convenience testing command for other reviewers:

cargo run --example solari --features="bevy_solari" -- --pathtracer

I got curious to see if I could get an infinite mirror in the cornell box, but the reflections beyond a certain number of bounces don't show up. Maybe this is a setting somewhere that I am unaware of? Either way results are neat.
Screenshot 2025-07-22 at 1 39 13 AM

@NicTanghe
Copy link

NicTanghe commented Jul 23, 2025

Just came here to add that a 1 to 1 compatibility with the solari material system and materialx is disirable.

@JMS55
Copy link
Contributor Author

JMS55 commented Jul 23, 2025

There's vague plans to support MaterialX in bevy, but for solari, we're unlikely to support such a wide range of materials.

Raytracing is already super expensive, adding lots of varied materials on top makes it even slower :)

let B = TBN[1];
let N = TBN[2];

let wo_tangent = vec3(dot(wo, T), dot(wo, B), dot(wo, N));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If TBN is a mat3<f32>, this is just TBN * wo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm this is the code we use everywhere else in bevy 😅

var wi_tangent: vec3<f32>;
if rand_f(rng) < diffuse_weight {
wi = sample_cosine_hemisphere(ray_hit.world_normal, rng);
wi_tangent = vec3(dot(wi, T), dot(wi, B), dot(wi, N));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

wi_tangent = vec3(dot(wi, T), dot(wi, B), dot(wi, N));
} else {
wi_tangent = sample_ggx_vndf(wo_tangent, ray_hit.material.roughness, rng);
wi = wi_tangent.x * T + wi_tangent.y * B + wi_tangent.z * N;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this is a mul with the transpose.

wi = wi_tangent.x * T + wi_tangent.y * B + wi_tangent.z * N;
}

let diffuse_pdf = dot(wi, ray_hit.world_normal) / PI;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have wi_tangent here, can just use the Z component (I assume that's up) instead of the dot.

@JMS55 JMS55 requested review from SparkyPotato and atlv24 July 25, 2025 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

5 participants