-
-
Notifications
You must be signed in to change notification settings - Fork 4k
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
base: main
Are you sure you want to change the base?
Changes from 34 commits
90e02c7
c73405b
f340c77
dfb3401
bf5ed11
d80b8ef
0ecbd8f
18b5d1f
c474114
b143c10
b4a2f77
09f36c4
82519a5
02841d7
3ebb7d4
3df77e2
6f9b1b5
4714d4e
92bc08b
454a861
548f73f
aa4c545
140baf2
eb84298
ca464f1
5c5f099
aefcddf
b377f53
7430d90
be3142b
2f8a1a4
65b9caf
47a4d04
ae3aa09
e79d7ae
9aea643
70f8ad8
fb0cc10
b1464ca
5761e40
2b2b3c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
#import bevy_core_pipeline::tonemapping::tonemapping_luminance as luminance | ||
#import bevy_pbr::pbr_functions::calculate_tbn_mikktspace | ||
#import bevy_pbr::utils::{rand_f, rand_vec2f, sample_cosine_hemisphere} | ||
#import bevy_render::maths::PI | ||
#import bevy_render::view::View | ||
#import bevy_solari::sampling::sample_random_light | ||
#import bevy_solari::scene_bindings::{trace_ray, resolve_ray_hit_full, RAY_T_MIN, RAY_T_MAX} | ||
#import bevy_solari::brdf::evaluate_brdf | ||
#import bevy_solari::sampling::{sample_random_light, sample_ggx_vndf, ggx_vndf_pdf} | ||
#import bevy_solari::scene_bindings::{trace_ray, resolve_ray_hit_full, ResolvedRayHitFull, RAY_T_MIN, RAY_T_MAX} | ||
|
||
@group(1) @binding(0) var accumulation_texture: texture_storage_2d<rgba32float, read_write>; | ||
@group(1) @binding(1) var view_output: texture_storage_2d<rgba16float, write>; | ||
|
@@ -39,28 +41,26 @@ fn pathtrace(@builtin(global_invocation_id) global_id: vec3<u32>) { | |
let ray_hit = trace_ray(ray_origin, ray_direction, ray_t_min, RAY_T_MAX, RAY_FLAG_NONE); | ||
if ray_hit.kind != RAY_QUERY_INTERSECTION_NONE { | ||
let ray_hit = resolve_ray_hit_full(ray_hit); | ||
|
||
// Evaluate material BRDF | ||
let diffuse_brdf = ray_hit.material.base_color / PI; | ||
let wo = -ray_direction; | ||
|
||
// Use emissive only on the first ray (coming from the camera) | ||
if ray_t_min == 0.0 { radiance = ray_hit.material.emissive; } | ||
|
||
// Sample direct lighting | ||
let direct_lighting = sample_random_light(ray_hit.world_position, ray_hit.world_normal, &rng); | ||
radiance += throughput * diffuse_brdf * direct_lighting.radiance * direct_lighting.inverse_pdf; | ||
let direct_lighting_brdf = evaluate_brdf(ray_hit.world_normal, wo, direct_lighting.wi, ray_hit.material); | ||
radiance += throughput * direct_lighting.radiance * direct_lighting.inverse_pdf * direct_lighting_brdf; | ||
|
||
// Sample new ray direction from the material BRDF for next bounce | ||
ray_direction = sample_cosine_hemisphere(ray_hit.world_normal, &rng); | ||
|
||
// Update other variables for next bounce | ||
let next_bounce = importance_sample_next_bounce(wo, ray_hit, &rng); | ||
ray_direction = next_bounce.wi; | ||
ray_origin = ray_hit.world_position; | ||
ray_t_min = RAY_T_MIN; | ||
|
||
// Update throughput for next bounce | ||
let cos_theta = dot(-ray_direction, ray_hit.world_normal); | ||
let cosine_hemisphere_pdf = cos_theta / PI; // Weight for the next bounce because we importance sampled the diffuse BRDF for the next ray direction | ||
throughput *= (diffuse_brdf * cos_theta) / cosine_hemisphere_pdf; | ||
let brdf = evaluate_brdf(ray_hit.world_normal, wo, next_bounce.wi, ray_hit.material); | ||
let cos_theta = dot(next_bounce.wi, ray_hit.world_normal); | ||
throughput *= (brdf * cos_theta) / next_bounce.pdf; | ||
|
||
// Russian roulette for early termination | ||
let p = luminance(throughput); | ||
|
@@ -77,3 +77,36 @@ fn pathtrace(@builtin(global_invocation_id) global_id: vec3<u32>) { | |
textureStore(accumulation_texture, global_id.xy, vec4(new_color, old_color.a + 1.0)); | ||
textureStore(view_output, global_id.xy, vec4(new_color, 1.0)); | ||
} | ||
|
||
struct NextBounce { | ||
wi: vec3<f32>, | ||
pdf: f32, | ||
} | ||
|
||
fn importance_sample_next_bounce(wo: vec3<f32>, ray_hit: ResolvedRayHitFull, rng: ptr<function, u32>) -> NextBounce { | ||
let diffuse_weight = 1.0 - ray_hit.material.metallic; | ||
let specular_weight = ray_hit.material.metallic; | ||
JMS55 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
let TBN = calculate_tbn_mikktspace(ray_hit.world_normal, ray_hit.world_tangent); | ||
let T = TBN[0]; | ||
let B = TBN[1]; | ||
let N = TBN[2]; | ||
|
||
let wo_tangent = vec3(dot(wo, T), dot(wo, B), dot(wo, N)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: vec3<f32>; | ||
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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
} 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And this is a mul with the transpose. |
||
} | ||
|
||
let diffuse_pdf = dot(wi, ray_hit.world_normal) / PI; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have |
||
let specular_pdf = ggx_vndf_pdf(wo_tangent, wi_tangent, ray_hit.material.roughness); | ||
let pdf = (diffuse_weight * diffuse_pdf) + (specular_weight * specular_pdf); | ||
|
||
return NextBounce(wi, pdf); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
#define_import_path bevy_solari::brdf | ||
|
||
#import bevy_pbr::lighting::{F_AB, D_GGX, V_SmithGGXCorrelated, fresnel, specular_multiscatter} | ||
#import bevy_pbr::pbr_functions::{calculate_diffuse_color, calculate_F0} | ||
#import bevy_render::maths::PI | ||
#import bevy_solari::scene_bindings::ResolvedMaterial | ||
|
||
fn evaluate_brdf( | ||
world_normal: vec3<f32>, | ||
wo: vec3<f32>, | ||
wi: vec3<f32>, | ||
material: ResolvedMaterial, | ||
) -> vec3<f32> { | ||
let diffuse_brdf = diffuse_brdf(material.base_color, material.metallic); | ||
let specular_brdf = specular_brdf( | ||
world_normal, | ||
wo, | ||
wi, | ||
material.base_color, | ||
material.metallic, | ||
material.reflectance, | ||
material.perceptual_roughness, | ||
material.roughness, | ||
); | ||
return diffuse_brdf + specular_brdf; | ||
} | ||
|
||
fn diffuse_brdf(base_color: vec3<f32>, metallic: f32) -> vec3<f32> { | ||
let diffuse_color = calculate_diffuse_color(base_color, metallic, 0.0, 0.0); | ||
return diffuse_color / PI; | ||
} | ||
|
||
fn specular_brdf( | ||
N: vec3<f32>, | ||
V: vec3<f32>, | ||
L: vec3<f32>, | ||
base_color: vec3<f32>, | ||
metallic: f32, | ||
reflectance: vec3<f32>, | ||
perceptual_roughness: f32, | ||
roughness: f32, | ||
) -> vec3<f32> { | ||
let H = normalize(L + V); | ||
let NdotL = saturate(dot(N, L)); | ||
let NdotH = saturate(dot(N, H)); | ||
let LdotH = saturate(dot(L, H)); | ||
let NdotV = max(dot(N, V), 0.0001); | ||
|
||
let F0 = calculate_F0(base_color, metallic, reflectance); | ||
let F_ab = F_AB(perceptual_roughness, NdotV); | ||
|
||
let D = D_GGX(roughness, NdotH); | ||
let Vs = V_SmithGGXCorrelated(roughness, NdotV, NdotL); | ||
let F = fresnel(F0, LdotH); | ||
return specular_multiscatter(D, Vs, F, F0, F_ab, 1.0); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.