Skip to content

Commit

Permalink
ported pbr test minus bloom
Browse files Browse the repository at this point in the history
  • Loading branch information
schell committed Dec 22, 2023
1 parent 934633f commit 18cbaac
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 23 deletions.
29 changes: 29 additions & 0 deletions DEVLOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# devlog

## Sat Dec 23, 2023

I've ported over a majority of the tests to the GLTF-on-the-slab implementation.
I'm currently working on the big PBR test and having trouble with the skybox, which
is rendering all black...

Debugging rabbit hole:
* So is it even running?
- Yes, logging shows that it's running.
* Could it be it needs to be run in its own render pass?
* Before I even check that, I see that the skybox's vertex shader uses the `instance_index` as the `Id` of the camera, and I'm passing `0..1` as the instance range in the draw call.
- So we need a way to pass the camera's `Id` to the skybox.
- I just added it as a field on `Skybox`
- Using that new field fixed that issue. Now I have an issue with bloom.

After fixing the skybox rendering it seems bloom isn't running.

Debugging rabbit hole:
* So is it even running?
- Yes, logging shows that it's running.
* Is the result being used downstream during tonemapping?
- It seems to be.
* Let's check to see that there isn't something funky when configuring the graph.
- Nothing I can tell there.
* Maybe print out the brightness texture and make sure it's populated?
* Losing steam here, especially since bloom needs to be re-done as "physically based".

TODO: Part out the

## Thu Dec 21, 2023

It's the solstice! My Dad's birthday, and another bug hunt in `renderling`.
Expand Down
7 changes: 6 additions & 1 deletion crates/renderling/src/bloom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,20 @@ impl BloomFilter {
queue: &wgpu::Queue,
hdr_surface: &crate::HdrSurface,
) -> Arc<wgpu::BindGroup> {
log::trace!("bloom running");
let brightness_texture = &hdr_surface.brightness_texture;
// update the size if the size has changed
let size = brightness_texture.texture.size();
let size = UVec2::new(size.width, size.height);
if size != *self.size_uniform {
let prev_size = *self.size_uniform;
if size != prev_size {
log::trace!(" bloom size changed from: {size:?}");
*self.size_uniform = size;
self.size_uniform.update(queue);
}

if brightness_texture.texture.size() != self.textures[0].texture.size() {
log::trace!(" brightness size changed");
let width = size.x;
let height = size.y;
self.textures = [
Expand All @@ -261,6 +265,7 @@ impl BloomFilter {

// if the brightness texture is not
if self.initial_bindgroup.is_none() {
log::trace!(" creating initial bindgroup");
self.initial_bindgroup = Some(
// initial bindgroup reads from brightness texture
create_bindgroup(
Expand Down
91 changes: 90 additions & 1 deletion crates/renderling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,95 @@ mod test {
// spheres with different metallic roughnesses lit by an environment map.
//
// see https://learnopengl.com/PBR/Lighting
fn pbr_metallic_roughness_spheres() {
fn gltf_pbr_metallic_roughness_spheres() {
let ss = 600;
let mut r =
Renderling::headless(ss, ss).with_background_color(Vec3::splat(0.0).extend(1.0));
let stage = r.new_stage();
stage.configure_graph(&mut r, true);

let radius = 0.5;
let ss = ss as f32;
let projection = camera::perspective(ss, ss);
let k = 7;
let diameter = 2.0 * radius;
let spacing = radius * 0.25;
let len = (k - 1) as f32 * (diameter + spacing);
let half = len / 2.0;
let view = camera::look_at(
Vec3::new(half, half, 1.6 * len),
Vec3::new(half, half, 0.0),
Vec3::Y,
);
let camera = stage.append(&Camera::new(projection, view));

let mut icosphere = icosahedron::Polyhedron::new_isocahedron(radius, 5);
icosphere.compute_triangle_normals();
let icosahedron::Polyhedron {
positions,
normals,
cells,
..
} = icosphere;
log::info!("icosphere created on CPU");

let to_vertex = |ndx: &usize| -> Vertex {
let p: [f32; 3] = positions[*ndx].0.into();
let n: [f32; 3] = normals[*ndx].0.into();
Vertex::default().with_position(p).with_normal(n)
};
let sphere_vertices = cells.iter().flat_map(|icosahedron::Triangle { a, b, c }| {
let p0 = to_vertex(&a);
let p1 = to_vertex(&b);
let p2 = to_vertex(&c);
vec![p0, p1, p2]
});
let sphere_primitive = stage.new_primitive(sphere_vertices, [], Id::NONE);
for i in 0..k {
let roughness = i as f32 / (k - 1) as f32;
let x = (diameter + spacing) * i as f32;
for j in 0..k {
let metallic = j as f32 / (k - 1) as f32;
let y = (diameter + spacing) * j as f32;
let mut prim = sphere_primitive;
prim.material = stage.append(&PbrMaterial {
albedo_factor: Vec4::new(1.0, 1.0, 1.0, 1.0),
metallic_factor: metallic,
roughness_factor: roughness,
..Default::default()
});
let _entity = stage.draw_unit(&RenderUnit {
camera,
vertex_count: prim.vertex_count,
node_path: stage.append_array(&[stage.append(&gl::GltfNode {
mesh: stage.append(&gl::GltfMesh {
primitives: stage.append_array(&[prim]),
..Default::default()
}),
translation: Vec3::new(x, y, 0.0),
..Default::default()
})]),
..Default::default()
});
}
}

let (device, queue) = r.get_device_and_queue_owned();
let hdr_image = SceneImage::from_hdr_path("../../img/hdr/resting_place.hdr").unwrap();
let skybox = crate::skybox::Skybox::new(&device, &queue, hdr_image, camera);
stage.set_skybox(skybox);
stage.set_has_bloom(true);

let img = r.render_image().unwrap();
img_diff::assert_img_eq("pbr_metallic_roughness_spheres.png", img);
}

#[test]
// Tests the initial implementation of pbr metallic roughness on an array of
// spheres with different metallic roughnesses lit by an environment map.
//
// see https://learnopengl.com/PBR/Lighting
fn legacy_pbr_metallic_roughness_spheres() {
let ss = 600;
let mut r =
Renderling::headless(ss, ss).with_background_color(Vec3::splat(0.0).extend(1.0));
Expand Down Expand Up @@ -1083,6 +1171,7 @@ mod test {
r.setup_render_graph(RenderGraphConfig {
scene: Some(scene),
with_screen_capture: true,
with_bloom: false,
..Default::default()
});

Expand Down
13 changes: 7 additions & 6 deletions crates/renderling/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ impl Scene {
skybox
} else if let Some(skybox_img) = skybox_image {
log::trace!("scene will build a skybox");
Skybox::new(&device, &queue, skybox_img)
Skybox::new(&device, &queue, skybox_img, Id::NONE)
} else {
log::trace!("skybox is empty");
Skybox::empty(&device, &queue)
Expand Down Expand Up @@ -585,7 +585,7 @@ impl Scene {
// skybox should change image
log::trace!("skybox changed");
constants.toggles.set_has_skybox(true);
*skybox = Skybox::new(device, queue, img);
*skybox = Skybox::new(device, queue, img, Id::NONE);
*environment_bindgroup = crate::skybox::create_skybox_bindgroup(
device,
constants,
Expand Down Expand Up @@ -1127,6 +1127,7 @@ pub fn tonemapping(
Move<BloomResult>,
),
) -> Result<(), SceneError> {
log::trace!("tonemapping");
let label = Some("tonemapping");
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label });
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
Expand All @@ -1144,10 +1145,10 @@ pub fn tonemapping(
render_pass.set_pipeline(&hdr_frame.tonemapping_pipeline);
render_pass.set_bind_group(0, &hdr_frame.texture_bindgroup, &[]);
render_pass.set_bind_group(1, hdr_frame.constants.bindgroup(), &[]);
let bloom_bg = bloom_result
.0
.as_deref()
.unwrap_or(&hdr_frame.no_bloom_bindgroup);
let bloom_bg = bloom_result.0.as_deref().unwrap_or_else(|| {
log::trace!(" no bloom bindgroup");
&hdr_frame.no_bloom_bindgroup
});
render_pass.set_bind_group(2, bloom_bg, &[]);
render_pass.draw(0..6, 0..1);
drop(render_pass);
Expand Down
14 changes: 12 additions & 2 deletions crates/renderling/src/skybox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ pub struct Skybox {
pub prefiltered_environment_cubemap: crate::Texture,
// Texture of the pre-computed brdf integration
pub brdf_lut: crate::Texture,
// `Id` of the camera to use for rendering the skybox.
//
// The camera is used to determine the orientation of the skybox.
pub camera: crate::shader::id::Id<crate::shader::stage::Camera>,
}

impl Skybox {
Expand All @@ -153,11 +157,16 @@ impl Skybox {
format: crate::SceneImageFormat::R32G32B32A32FLOAT,
apply_linear_transfer: false,
};
Self::new(device, queue, hdr_img)
Self::new(device, queue, hdr_img, crate::shader::id::Id::NONE)
}

/// Create a new `Skybox`.
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, hdr_img: SceneImage) -> Self {
pub fn new(
device: &wgpu::Device,
queue: &wgpu::Queue,
hdr_img: SceneImage,
camera: crate::shader::id::Id<crate::shader::stage::Camera>,
) -> Self {
log::trace!("creating skybox");
let equirectangular_texture = Skybox::hdr_texture_from_scene_image(device, queue, hdr_img);
let proj = Mat4::perspective_rh(std::f32::consts::FRAC_PI_2, 1.0, 0.1, 10.0);
Expand Down Expand Up @@ -260,6 +269,7 @@ impl Skybox {
irradiance_cubemap,
prefiltered_environment_cubemap,
brdf_lut,
camera,
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/renderling/src/slab.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! CPU side of slab storage.
// TODO: part out Id, Slab, etc into new "slab" libs.
// https://discord.com/channels/750717012564770887/750717499737243679/1187537792910229544
use std::{
ops::Deref,
sync::{atomic::AtomicUsize, Arc, RwLock},
Expand Down
37 changes: 24 additions & 13 deletions crates/renderling/src/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl From<SlabError> for StageError {
pub struct Stage {
pub(crate) slab: SlabBuffer,
pub(crate) atlas: Arc<RwLock<Atlas>>,
pub(crate) skybox: Arc<Mutex<Skybox>>,
pub(crate) skybox: Arc<RwLock<Skybox>>,
pub(crate) pipeline: Arc<Mutex<Option<Arc<wgpu::RenderPipeline>>>>,
pub(crate) skybox_pipeline: Arc<RwLock<Option<Arc<wgpu::RenderPipeline>>>>,
pub(crate) has_skybox: Arc<AtomicBool>,
Expand All @@ -83,7 +83,7 @@ impl Stage {
slab: SlabBuffer::new(&device, 256),
pipeline: Default::default(),
atlas: Arc::new(RwLock::new(atlas)),
skybox: Arc::new(Mutex::new(Skybox::empty(&device, &queue))),
skybox: Arc::new(RwLock::new(Skybox::empty(&device, &queue))),
skybox_pipeline: Default::default(),
has_skybox: Arc::new(AtomicBool::new(false)),
bloom: Arc::new(RwLock::new(BloomFilter::new(&device, &queue, 1, 1))),
Expand Down Expand Up @@ -211,7 +211,7 @@ impl Stage {
/// Set the skybox.
pub fn set_skybox(&self, skybox: Skybox) {
// UNWRAP: if we can't acquire the lock we want to panic.
let mut guard = self.skybox.lock().unwrap();
let mut guard = self.skybox.write().unwrap();
*guard = skybox;
self.has_skybox
.store(true, std::sync::atomic::Ordering::Relaxed);
Expand Down Expand Up @@ -335,7 +335,7 @@ impl Stage {
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &vertex_shader,
entry_point: "skybox::vertex",
entry_point: "skybox::slabbed_vertex",
buffers: &[],
},
primitive: wgpu::PrimitiveState {
Expand All @@ -361,12 +361,21 @@ impl Stage {
},
fragment: Some(wgpu::FragmentState {
module: &fragment_shader,
entry_point: "skybox::fragment_cubemap",
targets: &[Some(wgpu::ColorTargetState {
format: crate::hdr::HdrSurface::TEXTURE_FORMAT,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
// TODO: remove renderling_shader::skybox::fragment_cubemap after porting
// to GLTF
entry_point: "skybox::stage_skybox_cubemap",
targets: &[
Some(wgpu::ColorTargetState {
format: crate::hdr::HdrSurface::TEXTURE_FORMAT,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
}),
Some(wgpu::ColorTargetState {
format: crate::hdr::HdrSurface::TEXTURE_FORMAT,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
}),
],
}),
multiview: None,
})
Expand Down Expand Up @@ -573,7 +582,7 @@ impl Stage {
&self.get_pipeline(),
// UNWRAP: if we can't acquire locks we want to panic
&self.atlas.read().unwrap(),
&self.skybox.lock().unwrap(),
&self.skybox.read().unwrap(),
));
*bindgroup = Some(b.clone());
b
Expand Down Expand Up @@ -776,9 +785,11 @@ pub fn stage_render(
}

if let Some(pipeline) = may_skybox_pipeline.as_ref() {
log::trace!("rendering skybox");
// UNWRAP: if we can't acquire the lock we want to panic.
let skybox = stage.skybox.read().unwrap();
render_pass.set_pipeline(pipeline);
render_pass.set_bind_group(0, &textures_bindgroup, &[]);
render_pass.draw(0..36, 0..1);
render_pass.draw(0..36, skybox.camera.inner()..skybox.camera.inner() + 1);
}
}
stage.queue.submit(std::iter::once(encoder.finish()));
Expand Down

0 comments on commit 18cbaac

Please sign in to comment.