Skip to content

Commit

Permalink
fixed problems with the skybox after slabbing
Browse files Browse the repository at this point in the history
  • Loading branch information
schell committed Jan 3, 2024
1 parent 745ae0c commit a3e384a
Show file tree
Hide file tree
Showing 27 changed files with 69 additions and 93 deletions.
32 changes: 19 additions & 13 deletions crates/renderling-shader/src/convolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use spirv_std::{
#[cfg(target_arch = "spirv")]
use spirv_std::num_traits::Float;

use crate::{pbr, IsVector};
use crate::{pbr, stage::Camera, IsVector};

fn radical_inverse_vdc(mut bits: u32) -> f32 {
bits = (bits << 16u32) | (bits >> 16u32);
Expand Down Expand Up @@ -149,40 +149,46 @@ pub fn integrate_brdf_doesnt_work(mut n_dot_v: f32, roughness: f32) -> Vec2 {
Vec2::new(a, b)
}

/// Expects a slab to contain a [`crate::stage::Camera`] followed by a `f32`
/// Used by [`vertex_prefilter_environment_cubemap`] to read the camera and
/// roughness values from the slab.
#[derive(Default, SlabItem)]
pub struct VertexPrefilterEnvironmentCubemapIds {
pub camera: Id<Camera>,
pub roughness: Id<f32>,
}

/// Uses the `instance_index` as the [`Id`] of a [`PrefilterEnvironmentIds`].
/// roughness value.
// TODO: merge this with the standard pass-thru cubemap vertex shader.
#[spirv(vertex)]
pub fn vertex_prefilter_environment_cubemap(
#[spirv(instance_index)] instance_index: u32,
#[spirv(vertex_index)] vertex_id: u32,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32],
out_pos: &mut Vec3,
out_roughness: &mut f32,
#[spirv(position)] gl_pos: &mut Vec4,
) {
let in_pos = crate::math::CUBE[vertex_id as usize];
let camera = slab.read::<crate::stage::Camera>(0u32.into());
let VertexPrefilterEnvironmentCubemapIds { camera, roughness } =
slab.read(Id::new(instance_index));
let camera = slab.read(camera);
*out_roughness = slab.read(roughness);
*out_pos = in_pos;
*gl_pos = camera.projection * camera.view * in_pos.extend(1.0);
}

/// Lambertian prefilter.
///
/// Expects a slab to contain a [`crate::stage::Camera`] followed by a `f32`
/// roughness value.
#[spirv(fragment)]
pub fn fragment_prefilter_environment_cubemap(
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32],
#[spirv(descriptor_set = 0, binding = 1)] environment_cubemap: &Cubemap,
#[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler,
in_pos: Vec3,
in_roughness: f32,
frag_color: &mut Vec4,
) {
let roughness = slab.read(Id::<f32>::from(crate::stage::Camera::slab_size()));
let mut n = in_pos.alt_norm_or_zero();
// `wgpu` and vulkan's y coords are flipped from opengl
n.y *= -1.0;
// These moves are redundant but the names have connections to the PBR
// equations.
let r = n;
let v = r;

Expand All @@ -191,12 +197,12 @@ pub fn fragment_prefilter_environment_cubemap(

for i in 0..SAMPLE_COUNT {
let xi = hammersley(i, SAMPLE_COUNT);
let h = importance_sample_ggx(xi, n, roughness);
let h = importance_sample_ggx(xi, n, in_roughness);
let l = (2.0 * v.dot(h) * h - v).alt_norm_or_zero();

let n_dot_l = n.dot(l).max(0.0);
if n_dot_l > 0.0 {
let mip_level = if roughness == 0.0 {
let mip_level = if in_roughness == 0.0 {
0.0
} else {
calc_lod(n_dot_l)
Expand Down
5 changes: 3 additions & 2 deletions crates/renderling-shader/src/skybox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,19 @@ pub fn fragment_cubemap(

/// Draws a cubemap.
///
/// Expects there to be a [`Camera`] in the slab at index 0.
/// Uses the `instance_index` as the [`Id`] for a [`Camera`].
///
/// Used to create a cubemap from an equirectangular image as well as cubemap
/// convolutions.
#[spirv(vertex)]
pub fn vertex_cubemap(
#[spirv(instance_index)] camera_index: u32,
#[spirv(vertex_index)] vertex_index: u32,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32],
local_pos: &mut Vec3,
#[spirv(position)] gl_pos: &mut Vec4,
) {
let camera = slab.read(Id::<Camera>::new(0));
let camera = slab.read(Id::<Camera>::new(camera_index));
let pos = crate::math::CUBE[vertex_index as usize];
*local_pos = pos;
*gl_pos = camera.projection * camera.view * pos.extend(1.0);
Expand Down
Binary file modified crates/renderling/src/linkage/convolution-fragment_bloom.spv
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified crates/renderling/src/linkage/skybox-vertex.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/skybox-vertex_cubemap.spv
Binary file not shown.
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-compute_cull_entities.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-gltf_fragment.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-gltf_vertex.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-main_fragment_scene.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-main_vertex_scene.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/tonemapping-fragment.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/tonemapping-vertex.spv
Binary file not shown.
Binary file not shown.
Binary file modified crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/tutorial-slabbed_vertices.spv
Binary file not shown.
Binary file not shown.
Binary file modified crates/renderling/src/linkage/ui-vertex.spv
Binary file not shown.
24 changes: 13 additions & 11 deletions crates/renderling/src/skybox.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! An HDR skybox.
use std::sync::Arc;

use crabslab::{CpuSlab, Slab, SlabItem, WgpuBuffer};
use crabslab::{CpuSlab, GrowableSlab, Slab, SlabItem, WgpuBuffer};
use glam::{Mat4, Vec3};

use crate::{atlas::AtlasImage, shader::stage::Camera};
use crate::{
atlas::AtlasImage,
shader::{convolution::VertexPrefilterEnvironmentCubemapIds, stage::Camera},
};

/// Render pipeline used to draw a skybox.
pub struct SkyboxRenderPipeline(pub wgpu::RenderPipeline);
Expand All @@ -17,7 +20,7 @@ pub fn skybox_bindgroup_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
Expand Down Expand Up @@ -86,7 +89,7 @@ pub fn create_skybox_render_pipeline(
});
SkyboxRenderPipeline(
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("skybox pipeline"),
label: Some("skybox render pipeline"),
layout: Some(&pp_layout),
vertex: wgpu::VertexState {
module: &vertex_shader,
Expand Down Expand Up @@ -468,8 +471,9 @@ impl Skybox {
);
let mut slab = CpuSlab::new(buffer);
// Write the camera at 0 and then the roughness
slab.write(0u32.into(), &Camera::default().with_projection(proj));
slab.write(Camera::slab_size().into(), &0.0f32);
let camera = slab.append(&Camera::default().with_projection(proj));
let roughness = slab.append(&0.0f32);
let id = slab.append(&VertexPrefilterEnvironmentCubemapIds { camera, roughness });
let (pipeline, bindgroup) =
crate::ibl::prefiltered_environment::create_pipeline_and_bindgroup(
&device,
Expand All @@ -485,8 +489,7 @@ impl Skybox {
let mip_height: u32 = 128 >> mip_level;

// update the roughness for these mips
let roughness = mip_level as f32 / 4.0;
slab.write(Camera::slab_size().into(), &roughness);
slab.write(roughness, &(mip_level as f32 / 4.0));

let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("specular convolution"),
Expand All @@ -508,7 +511,7 @@ impl Skybox {
);

// update the view to point at one of the cube faces
slab.write(0u32.into(), &Camera::new(proj, views[i]));
slab.write(camera, &Camera::new(proj, views[i]));

{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
Expand All @@ -526,7 +529,7 @@ impl Skybox {

render_pass.set_pipeline(&pipeline);
render_pass.set_bind_group(0, &bindgroup, &[]);
render_pass.draw(0..36, 0..1);
render_pass.draw(0..36, id.inner()..id.inner() + 1);
}

queue.submit([encoder.finish()]);
Expand Down Expand Up @@ -639,7 +642,6 @@ impl Skybox {
mod test {
use crabslab::GrowableSlab;
use glam::Vec3;
use img_diff::DiffCfg;

use super::*;
use crate::Renderling;
Expand Down
101 changes: 34 additions & 67 deletions crates/renderling/src/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub struct Stage {
pub(crate) slab: Arc<RwLock<CpuSlab<WgpuBuffer>>>,
pub(crate) atlas: Arc<RwLock<Atlas>>,
pub(crate) skybox: Arc<RwLock<Skybox>>,
pub(crate) skybox_bindgroup: Arc<Mutex<Option<Arc<wgpu::BindGroup>>>>,
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 Down Expand Up @@ -123,6 +124,7 @@ impl Stage {
pipeline: Default::default(),
atlas: Arc::new(RwLock::new(atlas)),
skybox: Arc::new(RwLock::new(Skybox::empty(device.clone(), queue.clone()))),
skybox_bindgroup: Default::default(),
skybox_pipeline: Default::default(),
has_skybox: Arc::new(AtomicBool::new(false)),
has_bloom: Arc::new(AtomicBool::new(false)),
Expand Down Expand Up @@ -305,76 +307,39 @@ impl Stage {
}

/// Return the skybox render pipeline, creating it if necessary.
pub fn get_skybox_pipeline(&self) -> Arc<wgpu::RenderPipeline> {
fn create_skybox_render_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline {
log::trace!("creating stage's skybox render pipeline");
let vertex_shader = device
.create_shader_module(wgpu::include_spirv!("linkage/skybox-slabbed_vertex.spv"));
let fragment_shader = device.create_shader_module(wgpu::include_spirv!(
"linkage/skybox-stage_skybox_cubemap.spv"
));
let stage_slab_buffers_layout = Stage::buffers_bindgroup_layout(&device);
let textures_layout = Stage::textures_bindgroup_layout(&device);
let label = Some("stage skybox");
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label,
bind_group_layouts: &[&stage_slab_buffers_layout, &textures_layout],
push_constant_ranges: &[],
});

device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("skybox pipeline"),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &vertex_shader,
entry_point: "skybox::slabbed_vertex",
buffers: &[],
},
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::LessEqual,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
mask: !0,
alpha_to_coverage_enabled: false,
count: 1,
},
fragment: Some(wgpu::FragmentState {
module: &fragment_shader,
// 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,
})],
}),
multiview: None,
})
}

pub fn get_skybox_pipeline_and_bindgroup(
&self,
) -> (Arc<wgpu::RenderPipeline>, Arc<wgpu::BindGroup>) {
// UNWRAP: safe because we're only ever called from the render thread.
let mut pipeline = self.skybox_pipeline.write().unwrap();
if let Some(pipeline) = pipeline.as_ref() {
let pipeline = if let Some(pipeline) = pipeline.as_ref() {
pipeline.clone()
} else {
let p = Arc::new(create_skybox_render_pipeline(&self.device));
let p = Arc::new(
crate::skybox::create_skybox_render_pipeline(
&self.device,
crate::hdr::HdrSurface::TEXTURE_FORMAT,
)
.0,
);
*pipeline = Some(p.clone());
p
}
};
// UNWRAP: safe because we're only ever called from the render thread.
let mut bindgroup = self.skybox_bindgroup.lock().unwrap();
let bindgroup = if let Some(bindgroup) = bindgroup.as_ref() {
bindgroup.clone()
} else {
let slab = self.slab.read().unwrap();
let bg = Arc::new(crate::skybox::create_skybox_bindgroup(
&self.device,
slab.as_ref().get_buffer(),
&self.skybox.read().unwrap().environment_cubemap,
));
*bindgroup = Some(bg.clone());
bg
};
(pipeline, bindgroup)
}

/// Return the main render pipeline, creating it if necessary.
Expand Down Expand Up @@ -734,8 +699,9 @@ pub fn stage_render(
let pipeline = stage.get_pipeline();
let slab_buffers_bindgroup = stage.get_slab_buffers_bindgroup();
let textures_bindgroup = stage.get_textures_bindgroup();
let may_skybox_pipeline = if stage.has_skybox.load(std::sync::atomic::Ordering::Relaxed) {
Some(stage.get_skybox_pipeline())
let has_skybox = stage.has_skybox.load(std::sync::atomic::Ordering::Relaxed);
let may_skybox_pipeline_and_bindgroup = if has_skybox {
Some(stage.get_skybox_pipeline_and_bindgroup())
} else {
None
};
Expand Down Expand Up @@ -780,11 +746,12 @@ pub fn stage_render(
* stage.number_of_indirect_draws()); */
}

if let Some(pipeline) = may_skybox_pipeline.as_ref() {
if let Some((pipeline, bindgroup)) = may_skybox_pipeline_and_bindgroup.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, bindgroup, &[]);
render_pass.draw(0..36, skybox.camera.inner()..skybox.camera.inner() + 1);
}
}
Expand Down

0 comments on commit a3e384a

Please sign in to comment.