-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Higher quality lightmap sampling #16740
base: main
Are you sure you want to change the base?
Changes from 1 commit
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 | ||||
---|---|---|---|---|---|---|
|
@@ -8,22 +8,72 @@ | |||||
// Samples the lightmap, if any, and returns indirect illumination from it. | ||||||
fn lightmap(uv: vec2<f32>, exposure: f32, instance_index: u32) -> vec3<f32> { | ||||||
let packed_uv_rect = mesh[instance_index].lightmap_uv_rect; | ||||||
let uv_rect = vec4<f32>(vec4<u32>( | ||||||
packed_uv_rect.x & 0xffffu, | ||||||
packed_uv_rect.x >> 16u, | ||||||
packed_uv_rect.y & 0xffffu, | ||||||
packed_uv_rect.y >> 16u)) / 65535.0; | ||||||
let uv_rect = vec4<f32>( | ||||||
unpack2x16unorm(packed_uv_rect.x), | ||||||
unpack2x16unorm(packed_uv_rect.y), | ||||||
); | ||||||
|
||||||
let lightmap_uv = mix(uv_rect.xy, uv_rect.zw, uv); | ||||||
|
||||||
// Bicubic 4-tap | ||||||
// https://developer.nvidia.com/gpugems/gpugems2/part-iii-high-quality-rendering/chapter-20-fast-third-order-texture-filtering | ||||||
// https://advances.realtimerendering.com/s2021/jpatry_advances2021/index.html#/111/0/2 | ||||||
let texture_size = vec2<f32>(textureDimensions(lightmaps_texture)); | ||||||
let texel_size = 1.0 / texture_size; | ||||||
let puv = lightmap_uv * texture_size + 0.5; | ||||||
let iuv = floor(puv); | ||||||
let fuv = fract(puv); | ||||||
let g0x = g0(fuv.x); | ||||||
let g1x = g1(fuv.x); | ||||||
let h0x = h0_approx(fuv.x); | ||||||
let h1x = h1_approx(fuv.x); | ||||||
let h0y = h0_approx(fuv.y); | ||||||
let h1y = h1_approx(fuv.y); | ||||||
let p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - 0.5) * texel_size; | ||||||
let p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - 0.5) * texel_size; | ||||||
let p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - 0.5) * texel_size; | ||||||
let p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * texel_size; | ||||||
let filtered_sample = g0(fuv.y) * (g0x * sample(p0) + g1x * sample(p1)) + | ||||||
g1(fuv.y) * (g0x * sample(p2) + g1x * sample(p3)); | ||||||
|
||||||
return filtered_sample * exposure; | ||||||
} | ||||||
|
||||||
fn sample(uv: vec2<f32>) -> vec3<f32> { | ||||||
// Mipmapping lightmaps is usually a bad idea due to leaking across UV | ||||||
// islands, so there's no harm in using mip level 0 and it lets us avoid | ||||||
// control flow uniformity problems. | ||||||
// | ||||||
// TODO(pcwalton): Consider bicubic filtering. | ||||||
return textureSampleLevel( | ||||||
lightmaps_texture, | ||||||
lightmaps_sampler, | ||||||
lightmap_uv, | ||||||
0.0).rgb * exposure; | ||||||
return textureSampleLevel(lightmaps_texture, lightmaps_sampler, uv, 0.0).rgb; | ||||||
} | ||||||
|
||||||
fn w0(a: f32) -> f32 { | ||||||
return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0); | ||||||
} | ||||||
|
||||||
fn w1(a: f32) -> f32 { | ||||||
return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0); | ||||||
} | ||||||
|
||||||
fn w2(a: f32) -> f32 { | ||||||
return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0); | ||||||
} | ||||||
|
||||||
fn w3(a: f32) -> f32 { | ||||||
return (1.0 / 6.0) * (a * a * a); | ||||||
} | ||||||
|
||||||
fn g0(a: f32) -> f32 { | ||||||
return w0(a) + w1(a); | ||||||
} | ||||||
|
||||||
fn g1(a: f32) -> f32 { | ||||||
return w2(a) + w3(a); | ||||||
} | ||||||
|
||||||
fn h0_approx(a: f32) -> f32 { | ||||||
return 0.2 + a * (0.24 * a - 0.44); | ||||||
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. |
||||||
} | ||||||
|
||||||
fn h1_approx(a: f32) -> f32 { | ||||||
return 1.0 + a * (0.24 * a - 0.04); | ||||||
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. 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.
Suggested change
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. I plugged it into desmos. Both yours and my h1 approx have inaccuracies. The difference is whether it occurs before or after the midpoint. 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. Oops, I replaced the - with a +! Sign error. Ignore my comment, your code is fine the way it is |
||||||
} |
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.
nit: Odd indentation here
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.
Copy+pasted tabs :/. Fixed.