diff --git a/crates/renderling-shader/src/.#skybox.rs b/crates/renderling-shader/src/.#skybox.rs deleted file mode 120000 index 38d7b10a..00000000 --- a/crates/renderling-shader/src/.#skybox.rs +++ /dev/null @@ -1 +0,0 @@ -schell@Schells-MacBook-Pro-2.local.33429 \ No newline at end of file diff --git a/crates/renderling-shader/src/convolution.rs b/crates/renderling-shader/src/convolution.rs index d84321f2..70161a6f 100644 --- a/crates/renderling-shader/src/convolution.rs +++ b/crates/renderling-shader/src/convolution.rs @@ -1,6 +1,7 @@ //! Convolution shaders. //! //! These shaders convolve various functions to produce cached maps. +use crabslab::{Id, Slab, SlabItem}; use glam::{UVec2, Vec2, Vec3, Vec4, Vec4Swizzles}; use spirv_std::{ image::{Cubemap, Image2d}, @@ -11,7 +12,7 @@ use spirv_std::{ #[cfg(target_arch = "spirv")] use spirv_std::num_traits::Float; -use crate::{pbr, stage::GpuConstants, IsVector}; +use crate::{pbr, IsVector}; fn radical_inverse_vdc(mut bits: u32) -> f32 { bits = (bits << 16u32) | (bits >> 16u32); @@ -148,26 +149,35 @@ 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` +/// roughness value. +// TODO: merge this with the standard pass-thru cubemap vertex shader. #[spirv(vertex)] pub fn vertex_prefilter_environment_cubemap( - #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &GpuConstants, - in_pos: Vec3, + #[spirv(vertex_index)] vertex_id: u32, + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32], out_pos: &mut Vec3, #[spirv(position)] gl_pos: &mut Vec4, ) { + let in_pos = crate::math::CUBE[vertex_id as usize]; + let camera = slab.read::(0u32.into()); *out_pos = in_pos; - *gl_pos = constants.camera_projection * constants.camera_view * in_pos.extend(1.0); + *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(uniform, descriptor_set = 0, binding = 1)] roughness: &f32, - #[spirv(descriptor_set = 0, binding = 2)] environment_cubemap: &Cubemap, - #[spirv(descriptor_set = 0, binding = 3)] sampler: &Sampler, + #[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, frag_color: &mut Vec4, ) { + let roughness = slab.read(Id::::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; @@ -181,12 +191,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, 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 roughness == 0.0 { 0.0 } else { calc_lod(n_dot_l) @@ -273,15 +283,44 @@ pub fn fragment_bloom( *frag_color = result.extend(1.0); } +#[repr(C)] +#[derive(Clone, Copy)] +struct Vert { + pos: [f32; 3], + uv: [f32; 2], +} + +/// A screen-space quad. +const BRDF_VERTS: [Vert; 6] = { + let bl = Vert { + pos: [-1.0, -1.0, 0.0], + uv: [0.0, 1.0], + }; + let br = Vert { + pos: [1.0, -1.0, 0.0], + uv: [1.0, 1.0], + }; + let tl = Vert { + pos: [-1.0, 1.0, 0.0], + uv: [0.0, 0.0], + }; + let tr = Vert { + pos: [1.0, 1.0, 0.0], + uv: [1.0, 0.0], + }; + + [bl, br, tr, bl, tr, tl] +}; + #[spirv(vertex)] pub fn vertex_brdf_lut_convolution( - in_pos: glam::Vec3, - in_uv: glam::Vec2, + #[spirv(vertex_index)] vertex_id: u32, out_uv: &mut glam::Vec2, #[spirv(position)] gl_pos: &mut glam::Vec4, ) { - *out_uv = in_uv; - *gl_pos = in_pos.extend(1.0); + let Vert { pos, uv } = BRDF_VERTS[vertex_id as usize]; + *out_uv = Vec2::from(uv); + *gl_pos = Vec3::from(pos).extend(1.0); } #[spirv(fragment)] diff --git a/crates/renderling-shader/src/skybox.rs b/crates/renderling-shader/src/skybox.rs index e7dd9766..e75d9c4a 100644 --- a/crates/renderling-shader/src/skybox.rs +++ b/crates/renderling-shader/src/skybox.rs @@ -54,23 +54,23 @@ pub fn fragment_cubemap( *out_color = env_color.extend(1.0); } -/// Passes the singular `Vec3` position attribute to the fragment shader -/// unchanged, while transforming `gl_pos` by the camera projection*view; +/// Draws a cubemap. /// /// Expects there to be a [`Camera`] in the slab at index 0. /// /// Used to create a cubemap from an equirectangular image as well as cubemap /// convolutions. #[spirv(vertex)] -pub fn vertex_position_passthru( +pub fn vertex_cubemap( + #[spirv(vertex_index)] vertex_index: u32, #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32], - in_pos: Vec3, local_pos: &mut Vec3, #[spirv(position)] gl_pos: &mut Vec4, ) { let camera = slab.read(Id::::new(0)); - *local_pos = in_pos; - *gl_pos = camera.projection * camera.view * in_pos.extend(1.0); + let pos = crate::math::CUBE[vertex_index as usize]; + *local_pos = pos; + *gl_pos = camera.projection * camera.view * pos.extend(1.0); } /// Colors a skybox using an equirectangular texture. diff --git a/crates/renderling-shader/src/ui.rs b/crates/renderling-shader/src/ui.rs index 577f488e..b52d5bb0 100644 --- a/crates/renderling-shader/src/ui.rs +++ b/crates/renderling-shader/src/ui.rs @@ -2,6 +2,7 @@ //! //! This is mostly for rendering text. +use crabslab::SlabItem; use glam::{Mat4, UVec2, Vec2, Vec4}; use spirv_std::{image::Image2d, spirv, Sampler}; @@ -43,7 +44,7 @@ impl UiVertex { } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, SlabItem)] pub struct UiConstants { pub canvas_size: UVec2, pub camera_translation: Vec2, diff --git a/crates/renderling/src/atlas.rs b/crates/renderling/src/atlas.rs index 65dce57b..706c033a 100644 --- a/crates/renderling/src/atlas.rs +++ b/crates/renderling/src/atlas.rs @@ -527,6 +527,7 @@ mod test { }, Renderling, }; + use crabslab::GrowableSlab; use glam::{Vec2, Vec3, Vec4}; use super::*; @@ -551,7 +552,7 @@ mod test { fn atlas_uv_mapping() { let mut r = Renderling::headless(32, 32).with_background_color(Vec3::splat(0.0).extend(1.0)); - let stage = r.new_stage(); + let mut stage = r.new_stage(); stage.configure_graph(&mut r, true); let (projection, view) = crate::camera::default_ortho2d(32.0, 32.0); let camera = stage.append(&Camera { @@ -598,18 +599,20 @@ mod test { material_id, ) .build(); + let mesh = stage.append(&mesh); let node = stage.append(&GltfNode { - mesh: stage.append(&mesh), + mesh, ..Default::default() }); let transform = stage.append(&Transform { scale: Vec3::new(32.0, 32.0, 1.0), ..Default::default() }); + let node_path = stage.append_array(&[node]); let _unit = stage.draw_unit(&RenderUnit { camera, transform, - node_path: stage.append_array(&[node]), + node_path, vertex_count: 6, ..Default::default() }); @@ -628,7 +631,7 @@ mod test { let w = sheet_w * 3 + 2; let h = sheet_h; let mut r = Renderling::headless(w, h).with_background_color(Vec4::new(1.0, 1.0, 0.0, 1.0)); - let stage = r.new_stage(); + let mut stage = r.new_stage(); stage.configure_graph(&mut r, true); let (projection, view) = crate::camera::default_ortho2d(w as f32, h as f32); @@ -661,18 +664,21 @@ mod test { .modes .set_wrap_t(TextureAddressMode::MIRRORED_REPEAT); + let albedo_texture = stage.append(&clamp_tex); let clamp_material_id = stage.append(&PbrMaterial { - albedo_texture: stage.append(&clamp_tex), + albedo_texture, lighting_model: LightingModel::NO_LIGHTING, ..Default::default() }); + let albedo_texture = stage.append(&repeat_tex); let repeat_material_id = stage.append(&PbrMaterial { - albedo_texture: stage.append(&repeat_tex), + albedo_texture, lighting_model: LightingModel::NO_LIGHTING, ..Default::default() }); + let albedo_texture = stage.append(&mirror_tex); let mirror_material_id = stage.append(&PbrMaterial { - albedo_texture: stage.append(&mirror_tex), + albedo_texture, lighting_model: LightingModel::NO_LIGHTING, ..Default::default() }); @@ -709,50 +715,70 @@ mod test { p }; - let _clamp = stage.draw_unit(&RenderUnit { - camera, - node_path: stage.append_array(&[stage.append(&GltfNode { - mesh: stage.append(&GltfMesh { - primitives: stage.append_array(&[clamp_prim]), - ..Default::default() - }), + let _clamp = { + let primitives = stage.append_array(&[clamp_prim]); + let mesh = stage.append(&GltfMesh { + primitives, ..Default::default() - })]), - vertex_count: 6, - ..Default::default() - }); - let _repeat = stage.draw_unit(&RenderUnit { - camera, - node_path: stage.append_array(&[stage.append(&GltfNode { - mesh: stage.append(&GltfMesh { - primitives: stage.append_array(&[repeat_prim]), - ..Default::default() - }), + }); + let node = stage.append(&GltfNode { + mesh, ..Default::default() - })]), - vertex_count: 6, - transform: stage.append(&Transform { + }); + let node_path = stage.append_array(&[node]); + stage.draw_unit(&RenderUnit { + camera, + node_path, + vertex_count: 6, + ..Default::default() + }) + }; + let _repeat = { + let primitives = stage.append_array(&[repeat_prim]); + let mesh = stage.append(&GltfMesh { + primitives, + ..Default::default() + }); + let node = stage.append(&GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); + let transform = stage.append(&Transform { translation: Vec3::new(sheet_w + 1.0, 0.0, 0.0), ..Default::default() - }), - ..Default::default() - }); - let _mirror = stage.draw_unit(&RenderUnit { - camera, - node_path: stage.append_array(&[stage.append(&GltfNode { - mesh: stage.append(&GltfMesh { - primitives: stage.append_array(&[mirror_prim]), - ..Default::default() - }), + }); + stage.draw_unit(&RenderUnit { + camera, + node_path, + vertex_count: 6, + transform, ..Default::default() - })]), - vertex_count: 6, - transform: stage.append(&Transform { + }) + }; + let _mirror = { + let primitives = stage.append_array(&[mirror_prim]); + let mesh = stage.append(&GltfMesh { + primitives, + ..Default::default() + }); + let node = stage.append(&GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); + let transform = stage.append(&Transform { translation: Vec3::new(sheet_w as f32 * 2.0 + 2.0, 0.0, 0.0), ..Default::default() - }), - ..Default::default() - }); + }); + stage.draw_unit(&RenderUnit { + camera, + node_path, + vertex_count: 6, + transform, + ..Default::default() + }) + }; let img = r.render_image().unwrap(); img_diff::assert_img_eq("atlas/uv_wrapping.png", img); @@ -768,7 +794,7 @@ mod test { let w = sheet_w * 3 + 2; let h = sheet_h; let mut r = Renderling::headless(w, h).with_background_color(Vec4::new(1.0, 1.0, 0.0, 1.0)); - let stage = r.new_stage(); + let mut stage = r.new_stage(); stage.configure_graph(&mut r, true); let (projection, view) = crate::camera::default_ortho2d(w as f32, h as f32); @@ -802,18 +828,23 @@ mod test { .modes .set_wrap_t(TextureAddressMode::MIRRORED_REPEAT); + let albedo_texture = stage.append(&clamp_tex); let clamp_material_id = stage.append(&PbrMaterial { - albedo_texture: stage.append(&clamp_tex), + albedo_texture, lighting_model: LightingModel::NO_LIGHTING, ..Default::default() }); + + let albedo_texture = stage.append(&repeat_tex); let repeat_material_id = stage.append(&PbrMaterial { - albedo_texture: stage.append(&repeat_tex), + albedo_texture, lighting_model: LightingModel::NO_LIGHTING, ..Default::default() }); + + let albedo_texture = stage.append(&mirror_tex); let mirror_material_id = stage.append(&PbrMaterial { - albedo_texture: stage.append(&mirror_tex), + albedo_texture, lighting_model: LightingModel::NO_LIGHTING, ..Default::default() }); @@ -851,50 +882,70 @@ mod test { p }; - let _clamp = stage.draw_unit(&RenderUnit { - camera, - node_path: stage.append_array(&[stage.append(&GltfNode { - mesh: stage.append(&GltfMesh { - primitives: stage.append_array(&[clamp_prim]), - ..Default::default() - }), + let _clamp = { + let primitives = stage.append_array(&[clamp_prim]); + let mesh = stage.append(&GltfMesh { + primitives, ..Default::default() - })]), - vertex_count: 6, - ..Default::default() - }); - let _repeat = stage.draw_unit(&RenderUnit { - camera, - node_path: stage.append_array(&[stage.append(&GltfNode { - mesh: stage.append(&GltfMesh { - primitives: stage.append_array(&[repeat_prim]), - ..Default::default() - }), + }); + let node = stage.append(&GltfNode { + mesh, ..Default::default() - })]), - vertex_count: 6, - transform: stage.append(&Transform { + }); + let node_path = stage.append_array(&[node]); + stage.draw_unit(&RenderUnit { + camera, + node_path, + vertex_count: 6, + ..Default::default() + }) + }; + let _repeat = { + let primitives = stage.append_array(&[repeat_prim]); + let mesh = stage.append(&GltfMesh { + primitives, + ..Default::default() + }); + let node = stage.append(&GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); + let transform = stage.append(&Transform { translation: Vec3::new(sheet_w + 1.0, 0.0, 0.0), ..Default::default() - }), - ..Default::default() - }); - let _mirror = stage.draw_unit(&RenderUnit { - camera, - node_path: stage.append_array(&[stage.append(&GltfNode { - mesh: stage.append(&GltfMesh { - primitives: stage.append_array(&[mirror_prim]), - ..Default::default() - }), + }); + stage.draw_unit(&RenderUnit { + camera, + node_path, + transform, + vertex_count: 6, ..Default::default() - })]), - vertex_count: 6, - transform: stage.append(&Transform { + }) + }; + let _mirror = { + let primitives = stage.append_array(&[mirror_prim]); + let mesh = stage.append(&GltfMesh { + primitives, + ..Default::default() + }); + let node = stage.append(&GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); + let transform = stage.append(&Transform { translation: Vec3::new(sheet_w as f32 * 2.0 + 2.0, 0.0, 0.0), ..Default::default() - }), - ..Default::default() - }); + }); + stage.draw_unit(&RenderUnit { + camera, + node_path, + vertex_count: 6, + transform, + ..Default::default() + }) + }; let img = r.render_image().unwrap(); img_diff::assert_img_eq("atlas/negative_uv_wrapping.png", img); diff --git a/crates/renderling/src/cubemap.rs b/crates/renderling/src/cubemap.rs index 1c2174f0..f785778a 100644 --- a/crates/renderling/src/cubemap.rs +++ b/crates/renderling/src/cubemap.rs @@ -68,9 +68,8 @@ impl CubemapMakingRenderPipeline { /// images. pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { log::trace!("creating cubemap-making render pipeline with format '{format:?}'"); - let vertex_shader = device.create_shader_module(wgpu::include_spirv!( - "linkage/skybox-vertex_position_passthru.spv" - )); + let vertex_shader = + device.create_shader_module(wgpu::include_spirv!("linkage/skybox-vertex_cubemap.spv")); let fragment_shader = device.create_shader_module(wgpu::include_spirv!( "linkage/skybox-fragment_equirectangular.spv" )); @@ -86,17 +85,8 @@ impl CubemapMakingRenderPipeline { layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "skybox::vertex_position_passthru", - buffers: &[wgpu::VertexBufferLayout { - array_stride: { - let position_size = std::mem::size_of::(); - position_size as wgpu::BufferAddress - }, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![ - 0 => Float32x3 - ], - }], + entry_point: "skybox::vertex_cubemap", + buffers: &[], }, primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, diff --git a/crates/renderling/src/diffuse_irradiance.rs b/crates/renderling/src/diffuse_irradiance.rs index 9c83bed6..5e53a2fc 100644 --- a/crates/renderling/src/diffuse_irradiance.rs +++ b/crates/renderling/src/diffuse_irradiance.rs @@ -74,8 +74,8 @@ impl DiffuseIrradianceConvolutionRenderPipeline { /// Create the rendering pipeline that performs a convolution. pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { log::trace!("creating convolution render pipeline with format '{format:?}'"); - let vertex_shader = device - .create_shader_module(wgpu::include_spirv!("linkage/vertex_position_passthru.spv")); + let vertex_shader = + device.create_shader_module(wgpu::include_spirv!("linkage/vertex_cubemap.spv")); log::trace!("creating fragment shader"); let fragment_shader = device.create_shader_module(wgpu::include_wgsl!( "wgsl/diffuse_irradiance_convolution.wgsl" @@ -88,23 +88,15 @@ impl DiffuseIrradianceConvolutionRenderPipeline { bind_group_layouts: &[&bg_layout], push_constant_ranges: &[], }); + // TODO: merge irradiance pipeline with the pipeline in cubemap.rs let pipeline = DiffuseIrradianceConvolutionRenderPipeline(device.create_render_pipeline( &wgpu::RenderPipelineDescriptor { label: Some("convolution pipeline"), layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "skybox::vertex_position_passthru", - buffers: &[wgpu::VertexBufferLayout { - array_stride: { - let position_size = std::mem::size_of::(); - position_size as wgpu::BufferAddress - }, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![ - 0 => Float32x3 - ], - }], + entry_point: "skybox::vertex_cubemap", + buffers: &[], }, primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, diff --git a/crates/renderling/src/hdr.rs b/crates/renderling/src/hdr.rs index 391f6e22..0a09668a 100644 --- a/crates/renderling/src/hdr.rs +++ b/crates/renderling/src/hdr.rs @@ -1,7 +1,7 @@ //! High definition rendering types and techniques. //! //! Also includes bloom effect. -use crabslab::{CpuSlab, SlabItem, WgpuBuffer}; +use crabslab::{CpuSlab, Slab, SlabItem, WgpuBuffer}; use moongraph::*; use renderling_shader::tonemapping::TonemapConstants; @@ -16,7 +16,6 @@ use crate::{ /// See https://learnopengl.com/Advanced-Lighting/HDR. pub struct HdrSurface { pub hdr_texture: crate::Texture, - pub brightness_texture: crate::Texture, pub bindgroup: wgpu::BindGroup, pub tonemapping_pipeline: wgpu::RenderPipeline, pub slab: CpuSlab, @@ -60,13 +59,12 @@ impl HdrSurface { pub fn create_bindgroup( device: &wgpu::Device, - texture: &crate::Texture, + hdr_texture: &crate::Texture, slab_buffer: &wgpu::Buffer, ) -> wgpu::BindGroup { - let hdr_texture_layout = bindgroup_layout(&device, Some("HdrSurface texture bindgroup")); device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("HdrSurface texture bindgroup"), - layout: &hdr_texture_layout, + label: Some("HdrSurface bindgroup"), + layout: &bindgroup_layout(&device, Some("HdrSurface bindgroup")), entries: &[ wgpu::BindGroupEntry { binding: 0, @@ -78,35 +76,25 @@ impl HdrSurface { }, wgpu::BindGroupEntry { binding: 1, - resource: wgpu::BindingResource::TextureView(&texture.view), + resource: wgpu::BindingResource::TextureView(&hdr_texture.view), }, wgpu::BindGroupEntry { binding: 2, - resource: wgpu::BindingResource::Sampler(&texture.sampler), + resource: wgpu::BindingResource::Sampler(&hdr_texture.sampler), }, ], }) } - pub fn color_attachments(&self) -> [Option; 2] { - [ - Some(wgpu::RenderPassColorAttachment { - view: &self.hdr_texture.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, - }), - Some(wgpu::RenderPassColorAttachment { - view: &self.brightness_texture.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, - }), - ] + pub fn color_attachments(&self) -> [Option; 1] { + [Some(wgpu::RenderPassColorAttachment { + view: &self.hdr_texture.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, + }, + })] } } @@ -143,24 +131,6 @@ pub fn bindgroup_layout(device: &wgpu::Device, label: Option<&str>) -> wgpu::Bin ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering), count: None, }, - // bloom texture - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: false }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - // bloom sampler - wgpu::BindGroupLayoutEntry { - binding: 4, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering), - count: None, - }, ], }) } @@ -175,6 +145,8 @@ pub fn create_hdr_render_surface( ) -> Result<(HdrSurface,), WgpuStateError> { let buffer = WgpuBuffer::new(&*device, &*queue, TonemapConstants::slab_size()); let mut slab = CpuSlab::new(buffer); + // TODO: make the tonemapping configurable + slab.write(0u32.into(), &TonemapConstants::default()); let size = wgpu::Extent3d { width: size.width, height: size.height, @@ -225,7 +197,6 @@ pub fn create_hdr_render_surface( Ok((HdrSurface { bindgroup: HdrSurface::create_bindgroup(&device, &hdr_texture, slab.as_ref().get_buffer()), - brightness_texture: HdrSurface::create_texture(&device, &queue, size.width, size.height), hdr_texture, tonemapping_pipeline, slab, @@ -260,11 +231,7 @@ pub fn clear_surface_hdr_and_depth( &device, &queue, Some("clear_frame_and_depth"), - vec![ - &frame.view, - &hdr.hdr_texture.view, - &hdr.brightness_texture.view, - ], + vec![&frame.view, &hdr.hdr_texture.view], Some(&depth_view), color, ); diff --git a/crates/renderling/src/ibl/diffuse_irradiance.rs b/crates/renderling/src/ibl/diffuse_irradiance.rs index 6deeeedf..403c23a0 100644 --- a/crates/renderling/src/ibl/diffuse_irradiance.rs +++ b/crates/renderling/src/ibl/diffuse_irradiance.rs @@ -69,9 +69,8 @@ impl DiffuseIrradianceConvolutionRenderPipeline { /// Create the rendering pipeline that performs a convolution. pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { log::trace!("creating convolution render pipeline with format '{format:?}'"); - let vertex_shader = device.create_shader_module(wgpu::include_spirv!( - "../linkage/skybox-vertex_position_passthru.spv" - )); + let vertex_shader = device + .create_shader_module(wgpu::include_spirv!("../linkage/skybox-vertex_cubemap.spv")); log::trace!("creating fragment shader"); let fragment_shader = device.create_shader_module(wgpu::include_wgsl!( // TODO: rewrite this shader in Rust after atomics are added to naga spv @@ -85,23 +84,15 @@ impl DiffuseIrradianceConvolutionRenderPipeline { bind_group_layouts: &[&bg_layout], push_constant_ranges: &[], }); + // TODO: merge irradiance pipeline with cubemap let pipeline = DiffuseIrradianceConvolutionRenderPipeline(device.create_render_pipeline( &wgpu::RenderPipelineDescriptor { label: Some("convolution pipeline"), layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "skybox::vertex_position_passthru", - buffers: &[wgpu::VertexBufferLayout { - array_stride: { - let position_size = std::mem::size_of::(); - position_size as wgpu::BufferAddress - }, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![ - 0 => Float32x3 - ], - }], + entry_point: "skybox::vertex_cubemap", + buffers: &[], }, primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, diff --git a/crates/renderling/src/ibl/prefiltered_environment.rs b/crates/renderling/src/ibl/prefiltered_environment.rs index 2bb536e1..b662c672 100644 --- a/crates/renderling/src/ibl/prefiltered_environment.rs +++ b/crates/renderling/src/ibl/prefiltered_environment.rs @@ -21,7 +21,7 @@ pub fn create_pipeline_and_bindgroup( count: None, }, wgpu::BindGroupLayoutEntry { - binding: 2, + binding: 1, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, @@ -31,7 +31,7 @@ pub fn create_pipeline_and_bindgroup( count: None, }, wgpu::BindGroupLayoutEntry { - binding: 3, + binding: 2, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), count: None, @@ -74,13 +74,7 @@ pub fn create_pipeline_and_bindgroup( vertex: wgpu::VertexState { module: &vertex_shader, entry_point: "convolution::vertex_prefilter_environment_cubemap", - buffers: &[wgpu::VertexBufferLayout { - array_stride: 3 * std::mem::size_of::() as u64, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![ - 0 => Float32x3 - ], - }], + buffers: &[], }, primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, diff --git a/crates/renderling/src/lib.rs b/crates/renderling/src/lib.rs index 0285c2c0..57119862 100644 --- a/crates/renderling/src/lib.rs +++ b/crates/renderling/src/lib.rs @@ -53,12 +53,12 @@ mod renderer; mod skybox; mod stage; mod state; -#[cfg(feature = "text")] -mod text; +//#[cfg(feature = "text")] +//mod text; mod texture; mod tonemapping; //mod tutorial; -mod ui; +//mod ui; mod uniform; pub use atlas::*; @@ -70,11 +70,11 @@ pub use renderer::*; pub use skybox::*; pub use stage::*; pub use state::*; -#[cfg(feature = "text")] -pub use text::*; +//#[cfg(feature = "text")] +//pub use text::*; pub use texture::*; pub use tonemapping::*; -pub use ui::*; +//pub use ui::*; pub use uniform::*; pub mod color; @@ -216,8 +216,9 @@ mod test { .new_mesh() .with_primitive(right_tri_vertices(), [], Id::NONE) .build(); + let mesh = stage.append(&mesh); let node = stage.append(&gl::GltfNode { - mesh: stage.append(&mesh), + mesh, ..Default::default() }); let node_path = stage.append_array(&[node]); @@ -238,7 +239,7 @@ mod test { // We do this by writing over the previous transform in the stage. fn cmy_triangle_update_transform() { let mut r = Renderling::headless(100, 100).with_background_color(Vec4::splat(1.0)); - let stage = r.new_stage(); + let mut stage = r.new_stage(); stage.configure_graph(&mut r, true); let (projection, view) = default_ortho2d(100.0, 100.0); let camera = stage.append(&Camera::new(projection, view)); @@ -246,14 +247,16 @@ mod test { .new_mesh() .with_primitive(right_tri_vertices(), [], Id::NONE) .build(); + let mesh = stage.append(&mesh); let node = stage.append(&gl::GltfNode { - mesh: stage.append(&mesh), + mesh, ..Default::default() }); let transform = stage.append(&Transform::default()); + let node_path = stage.append_array(&[node]); let _tri = stage.draw_unit(&RenderUnit { camera, - node_path: stage.append_array(&[node]), + node_path, vertex_count: 3, transform, ..Default::default() @@ -261,16 +264,14 @@ mod test { let _ = r.render_image().unwrap(); - stage - .write( - transform, - &Transform { - translation: Vec3::new(100.0, 0.0, 0.0), - rotation: Quat::from_axis_angle(Vec3::Z, std::f32::consts::FRAC_PI_2), - scale: Vec3::new(0.5, 0.5, 1.0), - }, - ) - .unwrap(); + stage.write( + transform, + &Transform { + translation: Vec3::new(100.0, 0.0, 0.0), + rotation: Quat::from_axis_angle(Vec3::Z, std::f32::consts::FRAC_PI_2), + scale: Vec3::new(0.5, 0.5, 1.0), + }, + ); let img = r.render_image().unwrap(); img_diff::assert_img_eq("cmy_triangle_update_transform.png", img); @@ -333,20 +334,23 @@ mod test { .new_mesh() .with_primitive(vertices, [], Id::NONE) .build(); + let mesh = stage.append(&mesh); + let node = stage.append(&gl::GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); let transform = Transform { scale: Vec3::new(6.0, 6.0, 6.0), rotation: Quat::from_axis_angle(Vec3::Y, -std::f32::consts::FRAC_PI_4), ..Default::default() }; - let node = stage.append(&gl::GltfNode { - mesh: stage.append(&mesh), - ..Default::default() - }); + let transform = stage.append(&transform); let _cube = stage.draw_unit(&RenderUnit { camera, vertex_count, - node_path: stage.append_array(&[node]), - transform: stage.append(&transform), + node_path, + transform, ..Default::default() }); let img = r.render_image().unwrap(); @@ -372,8 +376,9 @@ mod test { .new_mesh() .with_primitive(vertices, [], Id::NONE) .build(); + let mesh = stage.append(&mesh); let node = stage.append(&gl::GltfNode { - mesh: stage.append(&mesh), + mesh, ..Default::default() }); let mut render_unit = RenderUnit { @@ -420,7 +425,7 @@ mod test { // update a field within a struct stored on the slab by offset. fn cmy_cube_remesh() { let mut r = Renderling::headless(100, 100).with_background_color(Vec4::splat(1.0)); - let stage = r.new_stage().with_lighting(false); + let mut stage = r.new_stage().with_lighting(false); stage.configure_graph(&mut r, true); let (projection, view) = camera::default_perspective(100.0, 100.0); let camera = stage.append(&Camera { @@ -435,8 +440,9 @@ mod test { .new_mesh() .with_primitive(pyramid_vertices, pyramid_indices, Id::NONE) .build(); + let mesh = stage.append(&pyramid_mesh); let pyramid_node = stage.append(&gl::GltfNode { - mesh: stage.append(&pyramid_mesh), + mesh, ..Default::default() }); let pyramid_node_path = stage.append_array(&[pyramid_node]); @@ -448,18 +454,22 @@ mod test { .new_mesh() .with_primitive(cube_vertices, cube_indices, Id::NONE) .build(); + let mesh = stage.append(&cube_mesh); let cube_node = stage.append(&gl::GltfNode { - mesh: stage.append(&cube_mesh), + mesh, ..Default::default() }); + let node_path = stage.append_array(&[cube_node]); + let transform = stage.append(&Transform { + scale: Vec3::new(10.0, 10.0, 10.0), + ..Default::default() + }); + let cube = stage.draw_unit(&RenderUnit { camera, vertex_count: cube_vertex_count as u32, - node_path: stage.append_array(&[cube_node]), - transform: stage.append(&Transform { - scale: Vec3::new(10.0, 10.0, 10.0), - ..Default::default() - }), + node_path, + transform, ..Default::default() }); @@ -469,9 +479,7 @@ mod test { // Update the cube mesh to a pyramid by overwriting the `.node_path` field // of `RenderUnit` - stage - .write(cube + RenderUnit::offset_of_node_path(), &pyramid_node_path) - .unwrap(); + stage.write(cube + RenderUnit::offset_of_node_path(), &pyramid_node_path); // we should see a pyramid let img = r.render_image().unwrap(); @@ -529,7 +537,7 @@ mod test { // mesh fn unlit_textured_cube_material() { let mut r = Renderling::headless(100, 100).with_background_color(Vec4::splat(0.0)); - let stage = r.new_stage(); + let mut stage = r.new_stage(); stage.configure_graph(&mut r, true); let (projection, view) = camera::default_perspective(100.0, 100.0); let camera = stage.append(&Camera { @@ -554,17 +562,20 @@ mod test { .new_mesh() .with_primitive(vertices, [], material_id) .build(); + let mesh = stage.append(&mesh); let node = stage.append(&gl::GltfNode { - mesh: stage.append(&mesh), + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); + let transform = stage.append(&Transform { + scale: Vec3::new(10.0, 10.0, 10.0), ..Default::default() }); let cube = stage.draw_unit(&RenderUnit { camera, - node_path: stage.append_array(&[node]), - transform: stage.append(&Transform { - scale: Vec3::new(10.0, 10.0, 10.0), - ..Default::default() - }), + node_path, + transform, vertex_count, ..Default::default() }); @@ -575,7 +586,7 @@ mod test { img_diff::assert_img_eq("unlit_textured_cube_material_before.png", img); // update the material's texture on the GPU - stage.write(sandstone_tex_id, &dirt_tex).unwrap(); + stage.write(sandstone_tex_id, &dirt_tex); // we should see a cube with a dirty texture let img = r.render_image().unwrap(); @@ -600,7 +611,8 @@ mod test { // now test the textures functionality let img = AtlasImage::from_path("../../img/cheetah.jpg").unwrap(); - let textures = stage.append_array(&stage.set_images([img]).unwrap()); + let textures = stage.set_images([img]).unwrap(); + let textures = stage.append_array(&textures); let cheetah_material = stage.append(&PbrMaterial { albedo_texture: textures.at(0), lighting_model: LightingModel::NO_LIGHTING, @@ -636,35 +648,49 @@ mod test { prim.material = Id::NONE; prim }; - let _unit = stage.draw_unit(&RenderUnit { - camera, - vertex_count: cheetah_primitive.vertex_count, - node_path: stage.append_array(&[stage.append(&gl::GltfNode { - mesh: stage.append(&gl::GltfMesh { - primitives: stage.append_array(&[color_primitive]), - ..Default::default() - }), + let _unit = { + let primitives = stage.append_array(&[color_primitive]); + let mesh = stage.append(&gl::GltfMesh { + primitives, ..Default::default() - })]), - ..Default::default() - }); - let _cheetah_unit = stage.draw_unit(&RenderUnit { - camera, - transform: stage.append(&Transform { + }); + let node = stage.append(&gl::GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); + + stage.draw_unit(&RenderUnit { + camera, + vertex_count: cheetah_primitive.vertex_count, + node_path, + ..Default::default() + }) + }; + let _cheetah_unit = { + let primitives = stage.append_array(&[cheetah_primitive]); + let mesh = stage.append(&gl::GltfMesh { + primitives, + ..Default::default() + }); + let node = stage.append(&gl::GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); + let transform = stage.append(&Transform { translation: Vec3::new(15.0, 35.0, 0.5), scale: Vec3::new(0.5, 0.5, 1.0), ..Default::default() - }), - vertex_count: cheetah_primitive.vertex_count, - node_path: stage.append_array(&[stage.append(&gl::GltfNode { - mesh: stage.append(&gl::GltfMesh { - primitives: stage.append_array(&[cheetah_primitive]), - ..Default::default() - }), + }); + stage.draw_unit(&RenderUnit { + camera, + transform, + vertex_count: cheetah_primitive.vertex_count, + node_path, ..Default::default() - })]), - ..Default::default() - }); + }) + }; let img = r.render_image().unwrap(); @@ -726,13 +752,16 @@ mod test { .collect::>(); let vertex_count = verts.len() as u32; let mesh = stage.new_mesh().with_primitive(verts, [], material).build(); + let mesh = stage.append(&mesh); + let node = stage.append(&gl::GltfNode { + mesh, + ..Default::default() + }); + let node_path = stage.append_array(&[node]); let _cube = stage.draw_unit(&RenderUnit { camera, vertex_count, - node_path: stage.append_array(&[stage.append(&gl::GltfNode { - mesh: stage.append(&mesh), - ..Default::default() - })]), + node_path, ..Default::default() }); let img = r.render_image().unwrap(); @@ -781,7 +810,7 @@ mod test { fn scene_parent_sanity() { let mut r = Renderling::headless(100, 100); r.set_background_color(Vec4::splat(0.0)); - let stage = r.new_stage(); + let mut stage = r.new_stage(); stage.configure_graph(&mut r, true); let (projection, view) = camera::default_ortho2d(100.0, 100.0); let camera = stage.append(&Camera::new(projection, view)); @@ -828,74 +857,83 @@ mod test { let red_node = stage.allocate::(); // Write the nodes now that we have references to them all - stage - .write( - root_node, - &gl::GltfNode { - children: stage.append_array(&[cyan_node]), - scale: Vec3::new(25.0, 25.0, 1.0), - ..Default::default() - }, - ) - .unwrap(); - stage - .write( - cyan_node, - &gl::GltfNode { - mesh: stage.append(&gl::GltfMesh { - primitives: stage.append_array(&[cyan_primitive]), - ..Default::default() - }), - children: stage.append_array(&[yellow_node]), - translation: Vec3::new(1.0, 1.0, 0.0), - ..Default::default() - }, - ) - .unwrap(); - stage - .write( - yellow_node, - &gl::GltfNode { - mesh: stage.append(&gl::GltfMesh { - primitives: stage.append_array(&[yellow_primitive]), - ..Default::default() - }), - children: stage.append_array(&[red_node]), - translation: Vec3::new(1.0, 1.0, 0.0), - ..Default::default() - }, - ) - .unwrap(); - stage - .write( - red_node, - &gl::GltfNode { - mesh: stage.append(&gl::GltfMesh { - primitives: stage.append_array(&[red_primitive]), - ..Default::default() - }), - translation: Vec3::new(1.0, 1.0, 0.0), - ..Default::default() - }, - ) - .unwrap(); + let children = stage.append_array(&[cyan_node]); + stage.write( + root_node, + &gl::GltfNode { + children, + scale: Vec3::new(25.0, 25.0, 1.0), + ..Default::default() + }, + ); + let primitives = stage.append_array(&[cyan_primitive]); + let children = stage.append_array(&[yellow_node]); + let mesh = stage.append(&gl::GltfMesh { + primitives, + ..Default::default() + }); + stage.write( + cyan_node, + &gl::GltfNode { + mesh, + children, + translation: Vec3::new(1.0, 1.0, 0.0), + ..Default::default() + }, + ); + + let primitives = stage.append_array(&[yellow_primitive]); + let children = stage.append_array(&[red_node]); + let mesh = stage.append(&gl::GltfMesh { + primitives, + ..Default::default() + }); + stage.write( + yellow_node, + &gl::GltfNode { + mesh, + children, + translation: Vec3::new(1.0, 1.0, 0.0), + ..Default::default() + }, + ); + + let primitives = stage.append_array(&[red_primitive]); + let mesh = stage.append(&gl::GltfMesh { + primitives, + ..Default::default() + }); + stage.write( + red_node, + &gl::GltfNode { + mesh, + translation: Vec3::new(1.0, 1.0, 0.0), + ..Default::default() + }, + ); + + let node_path = stage.append_array(&[root_node, cyan_node]); let _cyan_unit = stage.draw_unit(&RenderUnit { camera, vertex_count: 3, - node_path: stage.append_array(&[root_node, cyan_node]), + node_path, ..Default::default() }); + + let node_path = stage.append_array(&[root_node, cyan_node, yellow_node]); let _yellow_unit = stage.draw_unit(&RenderUnit { camera, vertex_count: 3, - node_path: stage.append_array(&[root_node, cyan_node, yellow_node]), + node_path, ..Default::default() }); + + let node_path = stage.append_array(&[root_node, cyan_node, yellow_node, red_node]); let _red_unit = stage.draw_unit(&RenderUnit { camera, vertex_count: 3, - node_path: stage.append_array(&[root_node, cyan_node, yellow_node, red_node]), + node_path, ..Default::default() }); @@ -975,17 +1013,21 @@ mod test { roughness_factor: roughness, ..Default::default() }); + let primitives = stage.append_array(&[prim]); + let mesh = stage.append(&gl::GltfMesh { + primitives, + ..Default::default() + }); + let node = stage.append(&gl::GltfNode { + mesh, + translation: Vec3::new(x, y, 0.0), + ..Default::default() + }); + let node_path = stage.append_array(&[node]); 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() - })]), + node_path, ..Default::default() }); } @@ -993,7 +1035,7 @@ mod test { let (device, queue) = r.get_device_and_queue_owned(); let hdr_image = AtlasImage::from_hdr_path("../../img/hdr/resting_place.hdr").unwrap(); - let skybox = crate::skybox::Skybox::new(&device, &queue, hdr_image, camera); + let skybox = crate::skybox::Skybox::new(device, queue, hdr_image, camera); stage.set_skybox(skybox); let img = r.render_image().unwrap(); diff --git a/crates/renderling/src/linkage/convolution-fragment_bloom.spv b/crates/renderling/src/linkage/convolution-fragment_bloom.spv index 2efb0137..d38905e1 100644 Binary files a/crates/renderling/src/linkage/convolution-fragment_bloom.spv and b/crates/renderling/src/linkage/convolution-fragment_bloom.spv differ diff --git a/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv b/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv index c085089e..3e02830b 100644 Binary files a/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv and b/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv differ diff --git a/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv b/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv index 37fc0096..271f3206 100644 Binary files a/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv and b/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv differ diff --git a/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv b/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv index 6b37843c..f93f0442 100644 Binary files a/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv and b/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv differ diff --git a/crates/renderling/src/linkage/convolution-vertex_generate_mipmap.spv b/crates/renderling/src/linkage/convolution-vertex_generate_mipmap.spv index 70f72ada..0f6af9d7 100644 Binary files a/crates/renderling/src/linkage/convolution-vertex_generate_mipmap.spv and b/crates/renderling/src/linkage/convolution-vertex_generate_mipmap.spv differ diff --git a/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv b/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv index eb663fbf..e3ddb416 100644 Binary files a/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv and b/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv differ diff --git a/crates/renderling/src/linkage/skybox-fragment_cubemap.spv b/crates/renderling/src/linkage/skybox-fragment_cubemap.spv index c6945d99..b985be73 100644 Binary files a/crates/renderling/src/linkage/skybox-fragment_cubemap.spv and b/crates/renderling/src/linkage/skybox-fragment_cubemap.spv differ diff --git a/crates/renderling/src/linkage/skybox-fragment_equirectangular.spv b/crates/renderling/src/linkage/skybox-fragment_equirectangular.spv index 3f80ad1e..19ffa5e7 100644 Binary files a/crates/renderling/src/linkage/skybox-fragment_equirectangular.spv and b/crates/renderling/src/linkage/skybox-fragment_equirectangular.spv differ diff --git a/crates/renderling/src/linkage/skybox-vertex.spv b/crates/renderling/src/linkage/skybox-vertex.spv index 779c8041..7415300b 100644 Binary files a/crates/renderling/src/linkage/skybox-vertex.spv and b/crates/renderling/src/linkage/skybox-vertex.spv differ diff --git a/crates/renderling/src/linkage/skybox-vertex_cubemap.spv b/crates/renderling/src/linkage/skybox-vertex_cubemap.spv new file mode 100644 index 00000000..59f35a06 Binary files /dev/null and b/crates/renderling/src/linkage/skybox-vertex_cubemap.spv differ diff --git a/crates/renderling/src/linkage/stage-compute_cull_entities.spv b/crates/renderling/src/linkage/stage-compute_cull_entities.spv index 70a1934e..8f6199b2 100644 Binary files a/crates/renderling/src/linkage/stage-compute_cull_entities.spv and b/crates/renderling/src/linkage/stage-compute_cull_entities.spv differ diff --git a/crates/renderling/src/linkage/stage-gltf_fragment.spv b/crates/renderling/src/linkage/stage-gltf_fragment.spv index 96020193..7c00fe26 100644 Binary files a/crates/renderling/src/linkage/stage-gltf_fragment.spv and b/crates/renderling/src/linkage/stage-gltf_fragment.spv differ diff --git a/crates/renderling/src/linkage/stage-gltf_vertex.spv b/crates/renderling/src/linkage/stage-gltf_vertex.spv index e24b45fe..2d13d2b9 100644 Binary files a/crates/renderling/src/linkage/stage-gltf_vertex.spv and b/crates/renderling/src/linkage/stage-gltf_vertex.spv differ diff --git a/crates/renderling/src/linkage/stage-main_fragment_scene.spv b/crates/renderling/src/linkage/stage-main_fragment_scene.spv index cbde1de8..ce093851 100644 Binary files a/crates/renderling/src/linkage/stage-main_fragment_scene.spv and b/crates/renderling/src/linkage/stage-main_fragment_scene.spv differ diff --git a/crates/renderling/src/linkage/stage-main_vertex_scene.spv b/crates/renderling/src/linkage/stage-main_vertex_scene.spv index 5e022a2a..ee38b8ff 100644 Binary files a/crates/renderling/src/linkage/stage-main_vertex_scene.spv and b/crates/renderling/src/linkage/stage-main_vertex_scene.spv differ diff --git a/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv b/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv index 8d717a72..a81e163e 100644 Binary files a/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv and b/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv differ diff --git a/crates/renderling/src/linkage/tonemapping-fragment.spv b/crates/renderling/src/linkage/tonemapping-fragment.spv index f7b72dec..3881f7e5 100644 Binary files a/crates/renderling/src/linkage/tonemapping-fragment.spv and b/crates/renderling/src/linkage/tonemapping-fragment.spv differ diff --git a/crates/renderling/src/linkage/tonemapping-vertex.spv b/crates/renderling/src/linkage/tonemapping-vertex.spv index 9b866b93..e312c4df 100644 Binary files a/crates/renderling/src/linkage/tonemapping-vertex.spv and b/crates/renderling/src/linkage/tonemapping-vertex.spv differ diff --git a/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv b/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv index d9155e82..78e2fa49 100644 Binary files a/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv and b/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv differ diff --git a/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv b/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv index 08234c40..84a57594 100644 Binary files a/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv and b/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv differ diff --git a/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv b/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv index ccf1d657..c3ca3bd5 100644 Binary files a/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv and b/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv differ diff --git a/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv b/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv index bf97013c..cd9b6ef4 100644 Binary files a/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv and b/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv differ diff --git a/crates/renderling/src/linkage/ui-fragment.spv b/crates/renderling/src/linkage/ui-fragment.spv index 8a70212e..1d1880bd 100644 Binary files a/crates/renderling/src/linkage/ui-fragment.spv and b/crates/renderling/src/linkage/ui-fragment.spv differ diff --git a/crates/renderling/src/linkage/ui-vertex.spv b/crates/renderling/src/linkage/ui-vertex.spv index c191daa7..61f7ecf6 100644 Binary files a/crates/renderling/src/linkage/ui-vertex.spv and b/crates/renderling/src/linkage/ui-vertex.spv differ diff --git a/crates/renderling/src/renderer.rs b/crates/renderling/src/renderer.rs index 9908966b..c8eec194 100644 --- a/crates/renderling/src/renderer.rs +++ b/crates/renderling/src/renderer.rs @@ -5,8 +5,8 @@ use snafu::prelude::*; use std::{ops::Deref, sync::Arc}; use crate::{ - hdr::HdrSurface, CreateSurfaceFn, Graph, RenderTarget, Stage, TextureError, UiScene, - UiSceneBuilder, View, ViewMut, WgpuStateError, + CreateSurfaceFn, Graph, RenderTarget, Stage, TextureError, + /* UiScene, UiSceneBuilder, */ View, ViewMut, WgpuStateError, }; #[derive(Debug, Snafu)] @@ -380,21 +380,21 @@ impl Renderling { Stage::new(device, queue) } - pub fn new_ui_scene(&self) -> UiSceneBuilder<'_> { - let (device, _) = self.get_device_and_queue_owned(); - let queue = self.get_queue(); - UiSceneBuilder::new(device.0.clone(), queue) - } + //pub fn new_ui_scene(&self) -> UiSceneBuilder<'_> { + // let (device, _) = self.get_device_and_queue_owned(); + // let queue = self.get_queue(); + // UiSceneBuilder::new(device.0.clone(), queue) + //} - pub fn empty_ui_scene(&self) -> UiScene { - self.new_ui_scene().build() - } + //pub fn empty_ui_scene(&self) -> UiScene { + // self.new_ui_scene().build() + //} - #[cfg(feature = "text")] - /// Create a new `GlyphCache` used to cache text rendering info. - pub fn new_glyph_cache(&self, fonts: Vec) -> crate::GlyphCache { - crate::GlyphCache::new(fonts) - } + //#[cfg(feature = "text")] + ///// Create a new `GlyphCache` used to cache text rendering info. + //pub fn new_glyph_cache(&self, fonts: Vec) -> + // crate::GlyphCache { crate::GlyphCache::new(fonts) + //} /// Render into an image. /// diff --git a/crates/renderling/src/skybox.rs b/crates/renderling/src/skybox.rs index 7ecf7743..22d5be60 100644 --- a/crates/renderling/src/skybox.rs +++ b/crates/renderling/src/skybox.rs @@ -3,9 +3,8 @@ use std::sync::Arc; use crabslab::{CpuSlab, Slab, SlabItem, WgpuBuffer}; use glam::{Mat4, Vec3}; -use renderling_shader::stage::GpuConstants; -use crate::{atlas::AtlasImage, shader::stage::Camera, Uniform}; +use crate::{atlas::AtlasImage, shader::stage::Camera}; /// Render pipeline used to draw a skybox. pub struct SkyboxRenderPipeline(pub wgpu::RenderPipeline); @@ -206,67 +205,30 @@ impl Skybox { Vec3::new(0.0, -1.0, 0.0), ), ]; - // Create unit cube for projections. - let cube_vertices: [[f32; 3]; 8] = [ - // front - [-1.0, -1.0, 1.0], - [1.0, -1.0, 1.0], - [1.0, 1.0, 1.0], - [-1.0, 1.0, 1.0], - // back - [-1.0, -1.0, -1.0], - [1.0, -1.0, -1.0], - [1.0, 1.0, -1.0], - [-1.0, 1.0, -1.0], - ]; - let cube_elements: [u16; 36] = [ - // front - 0, 1, 2, 2, 3, 0, // right - 1, 5, 6, 6, 2, 1, // back - 7, 6, 5, 5, 4, 7, // left - 4, 0, 3, 3, 7, 4, // bottom - 4, 5, 1, 1, 0, 4, // top - 3, 2, 6, 6, 7, 3, - ]; - - let unit_cube_mesh = crate::mesh::Mesh::new( - device, - Some("unit cube"), - cube_vertices, - Some(cube_elements), - ); // Create environment map. let environment_cubemap = Skybox::create_environment_map_from_hdr( - device, - queue, + device.clone(), + queue.clone(), &equirectangular_texture, - &unit_cube_mesh, proj, views, ); // Convolve the environment map. - let irradiance_cubemap = Skybox::create_irradiance_map( - device, - queue, - &environment_cubemap, - &unit_cube_mesh, - proj, - views, - ); + let irradiance_cubemap = + Skybox::create_irradiance_map(&device, &queue, &environment_cubemap, proj, views); // Generate specular IBL pre-filtered environment map. let prefiltered_environment_cubemap = Skybox::create_prefiltered_environment_map( - device, - queue, + &device, + &queue, &environment_cubemap, - &unit_cube_mesh, proj, views, ); - let brdf_lut = Skybox::create_precomputed_brdf_texture(device, queue); + let brdf_lut = Skybox::create_precomputed_brdf_texture(&device, &queue); Skybox { environment_cubemap, @@ -318,7 +280,6 @@ impl Skybox { device: crate::Device, queue: crate::Queue, hdr_texture: &crate::Texture, - unit_cube_mesh: &crate::mesh::Mesh, proj: Mat4, views: [Mat4; 6], ) -> crate::Texture { @@ -348,14 +309,13 @@ impl Skybox { ); Self::render_cubemap( - device, - queue, + &device, + &queue, "environment", &pipeline.0, &mut slab, proj, &bindgroup, - unit_cube_mesh, views, 512, Some(9), @@ -370,7 +330,6 @@ impl Skybox { slab: &mut CpuSlab, projection: Mat4, bindgroup: &wgpu::BindGroup, - unit_cube_mesh: &crate::mesh::Mesh, views: [Mat4; 6], texture_size: u32, mip_levels: Option, @@ -423,7 +382,7 @@ impl Skybox { render_pass.set_pipeline(pipeline); render_pass.set_bind_group(0, &bindgroup, &[]); - unit_cube_mesh.draw(&mut render_pass); + render_pass.draw(0..36, 0..1); } queue.submit([encoder.finish()]); @@ -452,7 +411,6 @@ impl Skybox { device: impl Into>, queue: impl Into>, environment_texture: &crate::Texture, - unit_cube_mesh: &crate::mesh::Mesh, proj: Mat4, views: [Mat4; 6], ) -> crate::Texture { @@ -487,7 +445,6 @@ impl Skybox { &mut slab, proj, &bindgroup, - unit_cube_mesh, views, 32, None, @@ -498,7 +455,6 @@ impl Skybox { device: impl Into>, queue: impl Into>, environment_texture: &crate::Texture, - unit_cube_mesh: &crate::mesh::Mesh, proj: Mat4, views: [Mat4; 6], ) -> crate::Texture { @@ -570,7 +526,7 @@ impl Skybox { render_pass.set_pipeline(&pipeline); render_pass.set_bind_group(0, &bindgroup, &[]); - unit_cube_mesh.draw(&mut render_pass); + render_pass.draw(0..36, 0..1); } queue.submit([encoder.finish()]); @@ -593,35 +549,6 @@ impl Skybox { device: &wgpu::Device, queue: &wgpu::Queue, ) -> crate::Texture { - #[repr(C)] - #[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] - struct Vert { - pos: [f32; 3], - uv: [f32; 2], - } - - let bl = Vert { - pos: [-1.0, -1.0, 0.0], - uv: [0.0, 1.0], - }; - let br = Vert { - pos: [1.0, -1.0, 0.0], - uv: [1.0, 1.0], - }; - let tl = Vert { - pos: [-1.0, 1.0, 0.0], - uv: [0.0, 0.0], - }; - let tr = Vert { - pos: [1.0, 1.0, 0.0], - uv: [1.0, 0.0], - }; - - let vertices = [bl, br, tr, bl, tr, tl]; - - let screen_space_quad_mesh = - crate::mesh::Mesh::from_vertices(device, Some("brdf_lut"), vertices); - let vertex_module = device.create_shader_module(wgpu::include_spirv!( "linkage/convolution-vertex_brdf_lut_convolution.spv" )); @@ -634,14 +561,7 @@ impl Skybox { vertex: wgpu::VertexState { module: &vertex_module, entry_point: "convolution::vertex_brdf_lut_convolution", - buffers: &[wgpu::VertexBufferLayout { - array_stride: (3 + 2) * std::mem::size_of::() as u64, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![ - 0 => Float32x3, - 1 => Float32x2 - ], - }], + buffers: &[], }, primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, @@ -708,7 +628,7 @@ impl Skybox { }); render_pass.set_pipeline(&pipeline); - screen_space_quad_mesh.draw(&mut render_pass); + render_pass.draw(0..6, 0..1); } queue.submit([encoder.finish()]); framebuffer @@ -717,6 +637,7 @@ impl Skybox { #[cfg(test)] mod test { + use crabslab::GrowableSlab; use glam::Vec3; use super::*; @@ -727,27 +648,28 @@ mod test { let mut r = Renderling::headless(600, 400); let proj = crate::camera::perspective(600.0, 400.0); let view = crate::camera::look_at(Vec3::new(0.0, 0.0, 2.0), Vec3::ZERO, Vec3::Y); - let mut builder = r.new_scene().with_camera(proj, view); - builder.add_skybox_image_from_path("../../img/hdr/resting_place.hdr"); - let scene = builder.build().unwrap(); + + let mut stage = r.new_stage(); + stage.configure_graph(&mut r, true); + + let camera = stage.append(&Camera::new(proj, view)); + let skybox = stage + .new_skybox_from_path("../../img/hdr/resting_place.hdr", camera) + .unwrap(); assert_eq!( wgpu::TextureFormat::Rgba16Float, - scene.skybox.irradiance_cubemap.texture.format() + skybox.irradiance_cubemap.texture.format() ); assert_eq!( wgpu::TextureFormat::Rgba16Float, - scene - .skybox - .prefiltered_environment_cubemap - .texture - .format() + skybox.prefiltered_environment_cubemap.texture.format() ); for i in 0..6 { // save out the irradiance face let copied_buffer = crate::Texture::read_from( - &scene.skybox.irradiance_cubemap.texture, + &skybox.irradiance_cubemap.texture, r.get_device(), r.get_queue(), 32, @@ -771,7 +693,7 @@ mod test { let mip_size = 128u32 >> mip_level; // save out the prefiltered environment faces' mips let copied_buffer = crate::Texture::read_from( - &scene.skybox.prefiltered_environment_cubemap.texture, + &skybox.prefiltered_environment_cubemap.texture, r.get_device(), r.get_queue(), mip_size as usize, @@ -798,11 +720,8 @@ mod test { } } - r.setup_render_graph(RenderGraphConfig { - scene: Some(scene), - with_screen_capture: true, - ..Default::default() - }); + stage.set_skybox(skybox); + let img = r.render_image().unwrap(); img_diff::assert_img_eq("skybox/hdr.png", img); } diff --git a/crates/renderling/src/stage.rs b/crates/renderling/src/stage.rs index bfa472a4..87a6b325 100644 --- a/crates/renderling/src/stage.rs +++ b/crates/renderling/src/stage.rs @@ -11,13 +11,14 @@ use crabslab::{Array, CpuSlab, GrowableSlab, Id, Slab, SlabItem, WgpuBuffer}; use moongraph::{View, ViewMut}; use renderling_shader::{ debug::DebugMode, - stage::{light::Light, RenderUnit, StageLegend}, + stage::{light::Light, Camera, RenderUnit, StageLegend}, texture::GpuTexture, }; use snafu::Snafu; use crate::{ - Atlas, AtlasError, AtlasImage, DepthTexture, Device, HdrSurface, Queue, Skybox, SlabError, + Atlas, AtlasError, AtlasImage, AtlasImageError, DepthTexture, Device, HdrSurface, Queue, + Skybox, SlabError, }; #[cfg(feature = "gltf")] @@ -79,12 +80,12 @@ impl Slab for Stage { fn write_indexed(&mut self, t: &T, index: usize) -> usize { // UNWRAP: if we can't acquire the lock we want to panic. - self.slab.read().unwrap().write_indexed(t, index) + self.slab.write().unwrap().write_indexed(t, index) } fn write_indexed_slice(&mut self, t: &[T], index: usize) -> usize { // UNWRAP: if we can't acquire the lock we want to panic. - self.slab.read().unwrap().write_indexed_slice(t, index) + self.slab.write().unwrap().write_indexed_slice(t, index) } } @@ -121,7 +122,7 @@ impl Stage { )))), pipeline: Default::default(), atlas: Arc::new(RwLock::new(atlas)), - skybox: Arc::new(RwLock::new(Skybox::empty(&device, &queue))), + skybox: Arc::new(RwLock::new(Skybox::empty(device.clone(), queue.clone()))), skybox_pipeline: Default::default(), has_skybox: Arc::new(AtomicBool::new(false)), has_bloom: Arc::new(AtomicBool::new(false)), @@ -136,31 +137,31 @@ impl Stage { } /// Set the debug mode. - pub fn set_debug_mode(&self, debug_mode: DebugMode) { + pub fn set_debug_mode(&mut self, debug_mode: DebugMode) { let id = Id::::from(StageLegend::offset_of_debug_mode()); self.write(id, &debug_mode); } /// Set the debug mode. - pub fn with_debug_mode(self, debug_mode: DebugMode) -> Self { + pub fn with_debug_mode(mut self, debug_mode: DebugMode) -> Self { self.set_debug_mode(debug_mode); self } /// Set whether the stage uses lighting. - pub fn set_has_lighting(&self, use_lighting: bool) { + pub fn set_has_lighting(&mut self, use_lighting: bool) { let id = Id::::from(StageLegend::offset_of_has_lighting()); self.write(id, &use_lighting); } /// Set whether the stage uses lighting. - pub fn with_lighting(self, use_lighting: bool) -> Self { + pub fn with_lighting(mut self, use_lighting: bool) -> Self { self.set_has_lighting(use_lighting); self } /// Set the lights to use for shading. - pub fn set_lights(&self, lights: Array) { + pub fn set_lights(&mut self, lights: Array) { let id = Id::>::from(StageLegend::offset_of_light_array()); self.write(id, &lights); } @@ -173,7 +174,7 @@ impl Stage { /// ## WARNING /// This invalidates any currently staged `GpuTextures`. pub fn set_images( - &self, + &mut self, images: impl IntoIterator, ) -> Result, StageError> { // UNWRAP: if we can't write the atlas we want to panic @@ -184,7 +185,8 @@ impl Stage { let _ = self.textures_bindgroup.lock().unwrap().take(); // The atlas size must be reset let size_id = Id::::from(StageLegend::offset_of_atlas_size()); - self.write(size_id, &atlas.size); + // UNWRAP: if we can't write to the stage legend we want to panic + self.slab.write().unwrap().write(size_id, &atlas.size); let textures = atlas .frames() @@ -354,18 +356,11 @@ impl Stage { // 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, - }), - ], + targets: &[Some(wgpu::ColorTargetState { + format: crate::hdr::HdrSurface::TEXTURE_FORMAT, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), + write_mask: wgpu::ColorWrites::ALL, + })], }), multiview: None, }) @@ -430,18 +425,11 @@ impl Stage { fragment: Some(wgpu::FragmentState { module: &fragment_shader, entry_point: "stage::gltf_fragment", - targets: &[ - Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba16Float, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - }), - Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba16Float, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - }), - ], + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba16Float, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), + write_mask: wgpu::ColorWrites::ALL, + })], }), multiview: None, }); @@ -468,7 +456,6 @@ impl Stage { let b = Arc::new({ let device: &wgpu::Device = &self.device; let pipeline: &wgpu::RenderPipeline = &self.get_pipeline(); - let slab_buffer = self.slab.as_ref(); let label = Some("stage slab buffer"); let stage_slab_buffers_bindgroup = device.create_bind_group(&wgpu::BindGroupDescriptor { @@ -579,7 +566,7 @@ impl Stage { } /// Draw the [`RenderUnit`] each frame, and immediately return its `Id`. - pub fn draw_unit(&self, unit: &RenderUnit) -> Id { + pub fn draw_unit(&mut self, unit: &RenderUnit) -> Id { let id = self.append(unit); let draw = DrawUnit { id, @@ -708,6 +695,21 @@ impl Stage { .as_ref() .block_on_read_raw(0, self.len()) } + + + pub fn new_skybox_from_path( + &self, + path: impl AsRef, + camera: Id, + ) -> Result { + let hdr = AtlasImage::from_hdr_path(path)?; + Ok(Skybox::new( + self.device.clone(), + self.queue.clone(), + hdr, + camera, + )) + } } /// A unit of work to be drawn. diff --git a/crates/renderling/src/stage/gltf_support.rs b/crates/renderling/src/stage/gltf_support.rs index 3344c79f..24485b2c 100644 --- a/crates/renderling/src/stage/gltf_support.rs +++ b/crates/renderling/src/stage/gltf_support.rs @@ -118,7 +118,7 @@ pub fn make_accessor(accessor: gltf::Accessor<'_>, views: &Array impl Stage { pub fn load_gltf_document_from_path( - &self, + &mut self, path: impl AsRef, ) -> Result<(gltf::Document, GltfDocument), StageGltfError> { let (document, buffers, images) = gltf::import(path)?; @@ -127,7 +127,7 @@ impl Stage { } pub fn load_gltf_document( - &self, + &mut self, document: &gltf::Document, buffer_data: Vec, images: Vec, @@ -137,7 +137,7 @@ impl Stage { for (i, buffer) in buffer_data.iter().enumerate() { let slice: &[u32] = bytemuck::cast_slice(&buffer); let buffer = self.append_array(slice); - self.write(buffers.at(i), &GltfBuffer(buffer))?; + self.write(buffers.at(i), &GltfBuffer(buffer)); } log::trace!("Loading views into the GPU"); @@ -154,7 +154,7 @@ impl Stage { length, stride, }; - self.write(id, &gltf_view)?; + self.write(id, &gltf_view); } log::trace!("Loading accessors into the GPU"); @@ -254,7 +254,7 @@ impl Stage { }; let texture_id = textures.at(i); log::trace!(" texture {i} {texture_id:?}: {texture:#?}"); - self.write(texture_id, &texture)?; + self.write(texture_id, &texture); } log::trace!("Creating materials"); @@ -407,7 +407,7 @@ impl Stage { } }; log::trace!(" material {material_id:?}: {material:#?}",); - self.write(material_id, &material)?; + self.write(material_id, &material); } let number_of_new_images = repacking.new_images_len(); @@ -425,7 +425,7 @@ impl Stage { let _ = self.textures_bindgroup.lock().unwrap().take(); // The atlas size must be reset let size_id = StageLegend::offset_of_atlas_size().into(); - self.write(size_id, &size)?; + self.slab.write().unwrap().write(size_id, &size); } fn log_accessor(gltf_accessor: gltf::Accessor<'_>) { @@ -734,7 +734,7 @@ impl Stage { weights, }; log::trace!(" writing primitive {id:?}:\n{prim:#?}"); - self.write(id, &prim)?; + self.write(id, &prim); } let weights = mesh.weights().unwrap_or(&[]); let weights = self.append_array(weights); @@ -744,7 +744,7 @@ impl Stage { primitives, weights, }, - )?; + ); } log::trace!("Loading lights"); let lights_array = self.allocate_array::( @@ -778,7 +778,7 @@ impl Stage { intensity, kind, }, - )?; + ); } } let lights = lights_array; @@ -835,7 +835,7 @@ impl Stage { light, skin, }, - )?; + ); } log::trace!("Loading skins"); @@ -889,7 +889,7 @@ impl Stage { let mut stored_samplers = vec![]; for (i, sampler) in animation.samplers().enumerate() { let sampler = create_sampler(accessors, sampler); - self.write(samplers.at(i), &sampler)?; + self.write(samplers.at(i), &sampler); // Store it later so we can figure out the index of the sampler // used by the channel. // @@ -916,12 +916,12 @@ impl Stage { .position(|s| s == &sampler) .context(MissingSamplerSnafu)?; let sampler = samplers.at(index); - self.write(channels.at(i), &GltfChannel { target, sampler })?; + self.write(channels.at(i), &GltfChannel { target, sampler }); } self.write( animations.at(animation.index()), &GltfAnimation { channels, samplers }, - )?; + ); } log::trace!("Loading scenes"); @@ -932,7 +932,7 @@ impl Stage { .map(|node| nodes.at(node.index())) .collect::>(); let nodes = self.append_array(&nodes); - self.write(scenes.at(scene.index()), &GltfScene { nodes })?; + self.write(scenes.at(scene.index()), &GltfScene { nodes }); } log::trace!("Done loading gltf"); @@ -1006,7 +1006,7 @@ impl Stage { /// Draw the given `gltf::Node` with the given `Camera`. /// `parents` is a list of the parent nodes of the given node. fn draw_gltf_node_with<'a>( - &self, + &mut self, gpu_doc: &GltfDocument, camera_id: Id, node: gltf::Node<'a>, @@ -1078,7 +1078,7 @@ impl Stage { /// Draw the given [`gltf::Node`] using the given [`Camera`] and return the /// ids of the render units that were created. pub fn draw_gltf_node( - &self, + &mut self, gpu_doc: &GltfDocument, camera_id: Id, node: gltf::Node<'_>, @@ -1089,7 +1089,7 @@ impl Stage { /// Draw the given [`gltf::Scene`] using the given [`Camera`] and return the /// ids of the render units that were created. pub fn draw_gltf_scene( - &self, + &mut self, gpu_doc: &GltfDocument, camera_id: Id, scene: gltf::Scene<'_>, @@ -1106,7 +1106,7 @@ impl Stage { /// ## Note /// This does **not** generate tangents or normals. pub fn new_primitive( - &self, + &mut self, vertices: impl IntoIterator, indices: impl IntoIterator, material: Id, @@ -1257,7 +1257,7 @@ impl Stage { /// [`gltf::Document`]. /// /// This is useful if you have non-GLTF assets that you want to render. - pub fn new_mesh(&self) -> GltfMeshBuilder { + pub fn new_mesh(&mut self) -> GltfMeshBuilder { GltfMeshBuilder::new(self) } } @@ -1267,12 +1267,12 @@ impl Stage { /// /// This is useful if you have non-GLTF assets that you want to render. pub struct GltfMeshBuilder<'a> { - stage: &'a Stage, + stage: &'a mut Stage, primitives: Vec, } impl<'a> GltfMeshBuilder<'a> { - pub fn new(stage: &'a Stage) -> Self { + pub fn new(stage: &'a mut Stage) -> Self { Self { stage, primitives: vec![], @@ -1314,18 +1314,14 @@ impl<'a> GltfMeshBuilder<'a> { /// /// This is useful if you have non-GLTF assets that you want to render. pub struct GltfDocumentBuilder<'a> { - stage: &'a Stage, + stage: &'a mut Stage, } impl<'a> GltfDocumentBuilder<'a> { - pub fn new(stage: &'a Stage) -> Self { + pub fn new(stage: &'a mut Stage) -> Self { Self { stage } } - pub fn new_mesh(&self) -> GltfMeshBuilder<'a> { - GltfMeshBuilder::new(self.stage) - } - pub fn build(self) -> GltfDocument { let accessors = Array::default(); let animations = Array::default(); @@ -1366,7 +1362,7 @@ mod test { }, Renderling, Stage, }; - use crabslab::{Array, Id, Slab}; + use crabslab::{Array, GrowableSlab, Id, Slab}; use glam::{Vec2, Vec3, Vec4, Vec4Swizzles}; use renderling_shader::stage::{GpuConstants, GpuEntity}; @@ -1452,7 +1448,7 @@ mod test { let projection = crate::camera::perspective(100.0, 50.0); let position = Vec3::new(1.0, 0.5, 1.5); let view = crate::camera::look_at(position, Vec3::new(1.0, 0.5, 0.0), Vec3::Y); - let stage = Stage::new(device.clone(), queue.clone()).with_lighting(false); + let mut stage = Stage::new(device.clone(), queue.clone()).with_lighting(false); stage.configure_graph(&mut r, true); let gpu_doc = stage .load_gltf_document(&document, buffers.clone(), images) @@ -1478,7 +1474,7 @@ mod test { let mut r = Renderling::headless(20, 20).with_background_color(Vec3::splat(0.0).extend(1.0)); let (device, queue) = r.get_device_and_queue_owned(); - let stage = Stage::new(device, queue).with_lighting(false); + let mut stage = Stage::new(device, queue).with_lighting(false); stage.configure_graph(&mut r, true); let (document, buffers, images) = gltf::import("../../gltf/gltfTutorial_003_MinimalGltfFile.gltf").unwrap(); @@ -1506,7 +1502,7 @@ mod test { // child primitive's geometry correctly. fn render_unit_transforms_primitive_geometry() { let mut r = Renderling::headless(50, 50).with_background_color(Vec4::splat(1.0)); - let stage = r.new_stage().with_lighting(false); + let mut stage = r.new_stage().with_lighting(false); stage.configure_graph(&mut r, true); let (projection, view) = crate::camera::default_ortho2d(50.0, 50.0); let camera = stage.append(&Camera::new(projection, view)); @@ -1529,8 +1525,9 @@ mod test { .with_color(white), ]; let primitive = stage.new_primitive(vertices, [0, 3, 2, 0, 2, 1], Id::NONE); + let primitives = stage.append_array(&[primitive]); let mesh = stage.append(&GltfMesh { - primitives: stage.append_array(&[primitive]), + primitives, ..Default::default() }); let node = stage.append(&GltfNode { @@ -1560,7 +1557,7 @@ mod test { fn gltf_images() { let mut r = Renderling::headless(100, 100).with_background_color(Vec4::splat(1.0)); let (device, queue) = r.get_device_and_queue_owned(); - let stage = Stage::new(device.clone(), queue.clone()).with_lighting(false); + let mut stage = Stage::new(device.clone(), queue.clone()).with_lighting(false); stage.configure_graph(&mut r, true); let (document, buffers, images) = gltf::import("../../gltf/cheetah_cone.glb").unwrap(); let gpu_doc = stage @@ -1577,29 +1574,28 @@ mod test { ..Default::default() }); println!("material_id: {:#?}", material_id); - let mesh = stage.append( - &stage - .new_mesh() - .with_primitive( - [ - Vertex::default() - .with_position([0.0, 0.0, 0.0]) - .with_uv0([0.0, 0.0]), - Vertex::default() - .with_position([1.0, 0.0, 0.0]) - .with_uv0([1.0, 0.0]), - Vertex::default() - .with_position([1.0, 1.0, 0.0]) - .with_uv0([1.0, 1.0]), - Vertex::default() - .with_position([0.0, 1.0, 0.0]) - .with_uv0([0.0, 1.0]), - ], - [0, 3, 2, 0, 2, 1], - material_id, - ) - .build(), - ); + let mesh = stage + .new_mesh() + .with_primitive( + [ + Vertex::default() + .with_position([0.0, 0.0, 0.0]) + .with_uv0([0.0, 0.0]), + Vertex::default() + .with_position([1.0, 0.0, 0.0]) + .with_uv0([1.0, 0.0]), + Vertex::default() + .with_position([1.0, 1.0, 0.0]) + .with_uv0([1.0, 1.0]), + Vertex::default() + .with_position([0.0, 1.0, 0.0]) + .with_uv0([0.0, 1.0]), + ], + [0, 3, 2, 0, 2, 1], + material_id, + ) + .build(); + let mesh = stage.append(&mesh); let node = stage.append(&GltfNode { mesh, ..Default::default() @@ -1630,7 +1626,7 @@ mod test { let mut r = Renderling::headless(size, size).with_background_color(Vec3::splat(0.0).extend(1.0)); let (device, queue) = r.get_device_and_queue_owned(); - let stage = Stage::new(device.clone(), queue.clone()) + let mut stage = Stage::new(device.clone(), queue.clone()) // There are no lights in the scene and the material isn't marked as "unlit", so // let's force it to be unlit. .with_lighting(false); @@ -1654,7 +1650,7 @@ mod test { let size = 600; let mut r = Renderling::headless(size, size).with_background_color(Vec3::splat(1.0).extend(1.0)); - let stage = r.new_stage().with_lighting(true).with_bloom(true); + let mut stage = r.new_stage().with_lighting(true).with_bloom(true); stage.configure_graph(&mut r, true); let (cpu_doc, gpu_doc) = stage .load_gltf_document_from_path("../../gltf/red_brick_03_1k.glb") @@ -1674,8 +1670,8 @@ mod test { let size = 100; let mut r = Renderling::headless(size, size).with_background_color(Vec3::splat(0.0).extend(1.0)); - let (device, queue) = r.get_device_and_queue_owned(); - let stage = Stage::new(device.clone(), queue.clone()) + let mut stage = r + .new_stage() // There are no lights in the scene and the material isn't marked as "unlit", so // let's force it to be unlit. .with_lighting(false); diff --git a/crates/renderling/src/ui.rs b/crates/renderling/src/ui.rs index f1d94df8..3039179f 100644 --- a/crates/renderling/src/ui.rs +++ b/crates/renderling/src/ui.rs @@ -7,6 +7,7 @@ use std::{ sync::Arc, }; +use crabslab::{CpuSlab, Slab, SlabItem, WgpuBuffer}; use glam::{UVec2, Vec2, Vec4}; use snafu::prelude::*; @@ -345,7 +346,8 @@ impl<'a> UiDrawObjectBuilder<'a> { pub struct UiScene { device: Arc, - constants: Uniform, + /// Slab containing `UiConstants`. + slab: CpuSlab, _default_texture: Texture, default_texture_bindgroup: wgpu::BindGroup, } @@ -353,22 +355,26 @@ pub struct UiScene { impl UiScene { pub fn new( device: Arc, - queue: &wgpu::Queue, + queue: Arc, canvas_size: UVec2, camera_translation: Vec2, ) -> Self { - let constants = Uniform::new( - &device, - UiConstants { + let buffer = WgpuBuffer::new( + device.clone(), + UiConstants::slab_size(), + wgpu::BufferUsages::empty(), + ); + let mut slab = CpuSlab::new(buffer); + slab.write( + 0u32.into(), + &UiConstants { canvas_size, camera_translation, }, - wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - wgpu::ShaderStages::VERTEX, ); let texture = Texture::new( &device, - queue, + &queue, Some("UiScene.default_texture"), None, 4,