Skip to content

Commit 6735dfb

Browse files
authored
feat: image based lighting part 2 (specular highlights) (#48)
* add brdf lut to skybox, brdf_lut tests * added IBL specular highlights * use mipmaps to soften prefiltering artifacts
1 parent 8fbbfab commit 6735dfb

86 files changed

Lines changed: 1429 additions & 476 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

DEVLOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# devlog
2+
3+
## Wed Aug 2, 2023
4+
5+
When generating mipmaps I ran into a problem where sampling the original texture was always coming up [0.0, 0.0 0.0, 0.0]. It turns out that the sampler was trying to read from the mipmap at level 1, and of course it didn't exist yet as that was the one I was trying to generate. The fix was to sample a different texture - one without slots for the mipmaps, then throw away that texture.
6+
7+
I have to generate mipmaps to smooth out the irradiance and prefiltered cubemaps that we use for pbr shading.
8+
9+
## Thur Aug 3, 2023
10+
11+
I greatly reduced the artifacts in the prefiltered environment cube used for specular highlights.
12+
I did this by using a simplified `calc_lod` and also by generating enough mipmaps.
13+
Previously I was only making 5 mip levels but the `calc_lod` was often requiring 21+!
14+
Of course the environment cubemap's face size is only 512, which leads to 9 mip levels total - so now I'm providing 9 mips.
15+
16+
I also noticed that the IBL diffuse irradiance samples were not aligned! Now the normal's Y is flipped in the irradiance convolution.

NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Just pro-cons on tech choices and little things I don't want to forget whil impl
6969
* [**Help inspecting buffers in Xcode** ](https://developer.apple.com/documentation/xcode/inspecting-buffers?changes=__9)
7070
* command that includes some vulkan debugging stuff
7171
- VK_LOADER_LAYERS_ENABLE='*validation' VK_LAYER_ENABLES=VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT DEBUG_PRINTF_TO_STDOUT=1
72+
* When generating mipmaps I ran into a problem where sampling the original texture was always coming up [0.0, 0.0 0.0, 0.0]. It turns out that the sampler was trying to read from the mipmap at level 1, and of course it didn't exist yet as that was the one I was trying to generate. The fix was to sample a different texture - one without slots for the mipmaps, then throw away that texture.
7273

7374
## PBR reference implementations
7475
* [khronos sample viewer](https://github.khronos.org/glTF-Sample-Viewer-Release/)

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ Shaders are written in Rust via `rust-gpu` where possible, falling back to `wgsl
4040

4141
Renderling takes a [forward+](https://takahiroharada.files.wordpress.com/2015/04/forward_plus.pdf) approach to rendering.
4242

43-
By default it uses a single uber-shader with a configurable lighting model per material.
44-
45-
This means each model may be shaded separately, with a different lighting style.
43+
By default it uses a single uber-shader for rendering.
4644

4745
- [ ] frustum culling
4846
- [ ] occlusion culling
@@ -54,8 +52,8 @@ This means each model may be shaded separately, with a different lighting style.
5452
- [x] high dynamic range
5553
- [x] skybox
5654
- image based lighting
57-
- [ ] diffuse
58-
- [ ] specular
55+
- [x] diffuse
56+
- [x] specular
5957
- [ ] msaa
6058
- [ ] bloom
6159
- [ ] ssao

crates/example/src/gltf.rs

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use std::time::Instant;
77
use renderling::{
88
debug::DebugChannel,
99
math::{Mat4, Vec3, Vec4},
10-
GltfLoader, GpuEntity, Renderling, Scene, ScreenSize, TweenProperty, UiDrawObjects, UiMode,
11-
UiVertex, ViewMut, SceneImage,
10+
GltfLoader, GpuEntity, Renderling, Scene, SceneImage, ScreenSize, TweenProperty, UiDrawObjects,
11+
UiMode, UiVertex, View, ViewMut,
1212
};
1313
use renderling_gpui::{Element, Gpui};
1414
use winit::event::KeyboardInput;
@@ -97,6 +97,7 @@ impl App {
9797
}
9898

9999
fn camera_position(radius: f32, phi: f32, theta: f32) -> Vec3 {
100+
// convert from spherical to cartesian
100101
let x = radius * theta.sin() * phi.cos();
101102
let y = radius * theta.sin() * phi.sin();
102103
let z = radius * theta.cos();
@@ -150,8 +151,13 @@ impl App {
150151
self.left_mb_down = false;
151152
self.last_cursor_position = None;
152153

153-
let mut builder = r.new_scene().with_debug_channel(DebugChannel::None);
154-
//let cross_loader = builder.gltf_load("/Users/schell/code/renderling/gltf/origin_cross.glb").unwrap();
154+
let mut builder = r
155+
.new_scene()
156+
.with_skybox_image_from_path("img/hdr/night.hdr")
157+
.with_debug_channel(DebugChannel::None);
158+
// let cross_loader =
159+
// builder.gltf_load("/Users/schell/code/renderling/gltf/origin_cross.glb").
160+
// unwrap();
155161
let loader = match builder.gltf_load(&file) {
156162
Ok(loader) => loader,
157163
Err(msg) => {
@@ -182,24 +188,6 @@ impl App {
182188
let length = min.distance(max);
183189
let radius = length * 1.25;
184190

185-
if loader.lights.len() == 0 {
186-
// These values were taken from the Khronos gltf-Sample-Viewer, which is a bit
187-
// of a reference implementation as far as GLTF viewers go.
188-
// See https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/5b1b7f48a8cb2b7aaef00d08fdba18ccc8dd331b/source/Renderer/renderer.js#L72
189-
let _key_light = builder
190-
.new_directional_light()
191-
.with_color(Vec4::ONE)
192-
.with_direction(Vec3::new(0.5, -0.7071, -0.5))
193-
.with_intensity(1.0)
194-
.build();
195-
let _fill_light = builder
196-
.new_directional_light()
197-
.with_color(Vec4::ONE)
198-
.with_direction(Vec3::new(-0.5, 0.7071, 0.5))
199-
.with_intensity(0.5)
200-
.build();
201-
}
202-
203191
let name = get_name(file);
204192
self.ui.set_text_title(format!("{name}"));
205193

@@ -309,7 +297,7 @@ impl App {
309297
}
310298
let time = animation.stored_timestamp % animation.length_in_seconds();
311299
for (id, tween_prop) in animation.get_properties_at_time(time).unwrap() {
312-
let mut ent = self.entities.get_mut(id.index()).unwrap();
300+
let ent = self.entities.get_mut(id.index()).unwrap();
313301
match tween_prop {
314302
TweenProperty::Translation(t) => {
315303
ent.position = t.extend(ent.position.w);
@@ -354,14 +342,12 @@ pub fn demo(
354342
skybox: Option<std::path::PathBuf>,
355343
) -> impl FnMut(&mut Renderling, Option<&winit::event::WindowEvent>) {
356344
let mut app = App::new(r);
357-
358345
if let Some(file) = model {
359346
app.load_gltf_model(r, file);
360347
}
361348
if let Some(file) = skybox {
362349
app.load_hdr_skybox(r, file);
363350
}
364-
365351
let mut event_state = renderling_gpui::EventState::default();
366352
move |r, ev: Option<&winit::event::WindowEvent>| {
367353
if let Some(ev) = ev {

crates/renderling-gpui/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,6 @@ impl Gpui {
297297
})
298298
.into(),
299299
};
300-
drop(r);
301300
let depth_texture = renderling::Texture::create_depth_texture(&device, width, height);
302301
let mut r = Renderling::new(
303302
target,

crates/renderling-shader/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@ glam = { version = "0.22", features = ["bytemuck"] }
2020
glam = { version = "0.22", features = ["debug-glam-assert", "bytemuck"] }
2121

2222
[target.'cfg(target_arch = "spirv")'.dependencies]
23-
glam = { version = "0.22", default-features = false, features = ["libm", "bytemuck"] }
23+
glam = { version = "0.22", default-features = false, features = ["libm", "bytemuck"] }
24+
25+
[dev-dependencies]
26+
image = "^0.24"
27+
img-diff = { path = "../img-diff" }

0 commit comments

Comments
 (0)