Skip to content

Commit

Permalink
WIP CPU-side sampling for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
schell committed Dec 12, 2023
1 parent e7e9dd4 commit e6ec7f9
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 53 deletions.
38 changes: 37 additions & 1 deletion crates/renderling-shader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ use core::ops::Mul;
use glam::{Quat, Vec3, Vec4Swizzles};
#[cfg(target_arch = "spirv")]
use spirv_std::num_traits::Float;
use spirv_std::num_traits::Zero;
use spirv_std::{
image::{Cubemap, Image2d},
num_traits::Zero,
Sampler,
};

pub mod array;
pub mod bits;
Expand Down Expand Up @@ -178,3 +182,35 @@ impl IsMatrix for glam::Mat4 {
(scale, rotation, translation)
}
}

pub trait IsSampler: Copy + Clone {}

impl IsSampler for Sampler {}

pub trait Sample2d {
type Sampler: IsSampler;

fn sample_by_lod(&self, sampler: Self::Sampler, uv: glam::Vec2, lod: f32) -> glam::Vec4;
}

impl Sample2d for Image2d {
type Sampler = Sampler;

fn sample_by_lod(&self, sampler: Self::Sampler, uv: glam::Vec2, lod: f32) -> glam::Vec4 {
self.sample_by_lod(sampler, uv, lod)
}
}

pub trait SampleCube {
type Sampler: IsSampler;

fn sample_by_lod(&self, sampler: Self::Sampler, uv: Vec3, lod: f32) -> glam::Vec4;
}

impl SampleCube for Cubemap {
type Sampler = Sampler;

fn sample_by_lod(&self, sampler: Self::Sampler, uv: Vec3, lod: f32) -> glam::Vec4 {
self.sample_by_lod(sampler, uv, lod)
}
}
22 changes: 11 additions & 11 deletions crates/renderling-shader/src/pbr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
slab::Slab,
stage::{light::LightStyle, GpuLight, LightType, LightingModel},
texture::GpuTexture,
IsVector,
IsSampler, IsVector, Sample2d, SampleCube,
};

/// Represents a material on the GPU.
Expand Down Expand Up @@ -173,18 +173,18 @@ fn outgoing_radiance(
(k_d * albedo / core::f32::consts::PI + specular) * radiance * n_dot_l
}

pub fn sample_irradiance(
irradiance: &Cubemap,
irradiance_sampler: &Sampler,
pub fn sample_irradiance<T: SampleCube<Sampler = S>, S: IsSampler>(
irradiance: &T,
irradiance_sampler: &S,
// Normal vector
n: Vec3,
) -> Vec3 {
irradiance.sample_by_lod(*irradiance_sampler, n, 0.0).xyz()
}

pub fn sample_specular_reflection(
prefiltered: &Cubemap,
prefiltered_sampler: &Sampler,
pub fn sample_specular_reflection<T: SampleCube<Sampler = S>, S: IsSampler>(
prefiltered: &T,
prefiltered_sampler: &S,
// camera position in world space
camera_pos: Vec3,
// fragment position in world space
Expand All @@ -200,9 +200,9 @@ pub fn sample_specular_reflection(
.xyz()
}

pub fn sample_brdf(
brdf: &Image2d,
brdf_sampler: &Sampler,
pub fn sample_brdf<T: Sample2d<Sampler = S>, S: IsSampler>(
brdf: &T,
brdf_sampler: &S,
// camera position in world space
camera_pos: Vec3,
// fragment position in world space
Expand Down Expand Up @@ -405,7 +405,7 @@ pub fn stage_shade_fragment(

LightStyle::Directional => {
let dir_light = slab.read(light.into_directional_id());
let l = -dir_light.direction.alt_norm_or_zero();
let l = (-dir_light.direction).alt_norm_or_zero();
let attenuation = dir_light.intensity;
lo += outgoing_radiance(
dir_light.color,
Expand Down
63 changes: 59 additions & 4 deletions crates/renderling-shader/src/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
pbr::{self, PbrMaterial},
slab::{Slab, Slabbed},
texture::GpuTexture,
IsMatrix, IsVector,
IsMatrix, IsSampler, IsVector, Sample2d, SampleCube,
};

pub mod light;
Expand Down Expand Up @@ -528,11 +528,11 @@ fn texture_color(
color
}

fn stage_texture_color(
fn stage_texture_color<T: Sample2d<Sampler = S>, S: IsSampler>(
texture_id: Id<GpuTexture>,
uv: Vec2,
atlas: &Image2d,
sampler: &Sampler,
atlas: &T,
sampler: &S,
atlas_size: UVec2,
slab: &[u32],
) -> Vec4 {
Expand Down Expand Up @@ -1157,6 +1157,61 @@ pub fn stage_fragment(
output: &mut Vec4,
brigtness: &mut Vec4,
) {
stage_fragment_impl(
atlas,
atlas_sampler,
irradiance,
irradiance_sampler,
prefiltered,
prefiltered_sampler,
brdf,
brdf_sampler,
slab,
in_camera,
in_material,
in_color,
in_uv0,
in_uv1,
in_norm,
in_tangent,
in_bitangent,
in_pos,
output,
brigtness,
);
}

#[allow(clippy::too_many_arguments)]
/// Scene fragment shader.
pub fn stage_fragment_impl<T, C, S>(
atlas: &T,
atlas_sampler: &S,
irradiance: &C,
irradiance_sampler: &S,
prefiltered: &C,
prefiltered_sampler: &S,
brdf: &T,
brdf_sampler: &S,

slab: &[u32],

in_camera: u32,
in_material: u32,
in_color: Vec4,
in_uv0: Vec2,
in_uv1: Vec2,
in_norm: Vec3,
in_tangent: Vec3,
in_bitangent: Vec3,
in_pos: Vec3,

output: &mut Vec4,
brigtness: &mut Vec4,
) where
T: Sample2d<Sampler = S>,
C: SampleCube<Sampler = S>,
S: IsSampler,
{
let StageLegend {
atlas_size,
debug_mode,
Expand Down
4 changes: 2 additions & 2 deletions crates/renderling-shader/src/stage/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn gltf_light_intensity_units(kind: gltf::khr_lights_punctual::Kind) -> &'st

#[repr(u32)]
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq)]
pub enum LightStyle {
Directional = 0,
Point = 1,
Expand Down Expand Up @@ -138,7 +138,7 @@ impl Slabbed for LightStyle {
/// A type-erased light Id that is used as a slab pointer to any light type.
#[repr(C)]
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[derive(Copy, Clone, Slabbed)]
#[derive(Copy, Clone, PartialEq, Slabbed)]
pub struct Light {
// The type of the light
pub light_type: LightStyle,
Expand Down
31 changes: 16 additions & 15 deletions crates/renderling/src/atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,27 +495,28 @@ impl Atlas {
}
}

#[cfg(test)]
impl Atlas {
fn atlas_img(&self, device: &wgpu::Device, queue: &wgpu::Queue) -> RgbaImage {
let buffer = crate::Texture::read(
&self.texture.texture,
device,
queue,
self.size.x as usize,
self.size.y as usize,
4,
1,
);
buffer.into_rgba(device).unwrap()
}
}

#[cfg(test)]
mod test {
use crate::Renderling;

use super::*;

impl Atlas {
fn atlas_img(&self, device: &wgpu::Device, queue: &wgpu::Queue) -> RgbaImage {
let buffer = crate::Texture::read(
&self.texture.texture,
device,
queue,
self.size.x as usize,
self.size.y as usize,
4,
1,
);
buffer.into_rgba(device).unwrap()
}
}

#[test]
fn can_merge_atlas() {
let r = Renderling::headless(100, 100);
Expand Down
98 changes: 81 additions & 17 deletions crates/renderling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub use atlas::*;
pub use buffer_array::*;
pub use camera::*;
pub use hdr::*;
use image::GenericImageView;
pub use renderer::*;
pub use scene::*;
pub use skybox::*;
Expand Down Expand Up @@ -106,6 +107,48 @@ pub mod shader {

pub use renderling_shader::stage::{GpuEntityInfo, LightingModel};

/// A CPU-side texture sampler.
///
/// Provided primarily for testing purposes.
#[derive(Debug, Clone, Copy)]
pub struct CpuSampler;

impl crate::shader::IsSampler for CpuSampler {}

#[derive(Debug)]
pub struct CpuTexture2d {
pub image: image::DynamicImage,
}

impl crate::shader::Sample2d for CpuTexture2d {
type Sampler = CpuSampler;

fn sample_by_lod(&self, _sampler: Self::Sampler, uv: glam::Vec2, _lod: f32) -> glam::Vec4 {
// TODO: lerp the CPU texture sampling
let image::Rgba([r, g, b, a]) = self.image.get_pixel(uv.x as u32, uv.y as u32);
glam::Vec4::new(
r as f32 / 255.0,
g as f32 / 255.0,
b as f32 / 255.0,
a as f32 / 255.0,
)
}
}

/// A CPU-side cubemap texture.
///
/// Provided primarily for testing purposes.
pub struct CpuCubemap;

impl crate::shader::SampleCube for CpuCubemap {
type Sampler = CpuSampler;

fn sample_by_lod(&self, _sampler: Self::Sampler, _uv: glam::Vec3, _lod: f32) -> glam::Vec4 {
// TODO: implement CPU-side cubemap sampling
glam::Vec4::ONE
}
}

/// Set up the render graph, including:
/// * 3d scene objects
/// * skybox
Expand Down Expand Up @@ -591,25 +634,31 @@ mod test {
}

impl VertexInvocation {
pub fn call(&mut self, slab: &[u32]) {
self.render_unit_id = Id::from(self.instance_index);
self.render_unit = slab.read(self.render_unit_id);
pub fn invoke(instance_index: u32, vertex_index: u32, slab: &[u32]) -> Self {
let mut v = Self {
instance_index,
vertex_index,
..Default::default()
};
v.render_unit_id = Id::from(v.instance_index);
v.render_unit = slab.read(v.render_unit_id);
new_stage_vertex(
self.instance_index,
self.vertex_index,
v.instance_index,
v.vertex_index,
slab,
&mut self.out_camera,
&mut self.out_material,
&mut self.out_color,
&mut self.out_uv0,
&mut self.out_uv1,
&mut self.out_norm,
&mut self.out_tangent,
&mut self.out_bitangent,
&mut self.out_pos,
&mut self.clip_pos,
&mut v.out_camera,
&mut v.out_material,
&mut v.out_color,
&mut v.out_uv0,
&mut v.out_uv1,
&mut v.out_norm,
&mut v.out_tangent,
&mut v.out_bitangent,
&mut v.out_pos,
&mut v.clip_pos,
);
self.ndc_pos = self.clip_pos.xyz() / self.clip_pos.w;
v.ndc_pos = v.clip_pos.xyz() / v.clip_pos.w;
v
}
}

Expand Down Expand Up @@ -1217,6 +1266,13 @@ mod test {
color: blue,
intensity: 10.0,
});
assert_eq!(
Light {
light_type: LightStyle::Directional,
index: dir_red.inner()
},
dir_red.into()
);
let lights = stage.append_array(&[dir_red.into(), dir_green.into(), dir_blue.into()]);
stage.set_lights(lights);

Expand All @@ -1237,13 +1293,21 @@ mod test {
..Default::default()
});

let _cube = stage.draw_unit(&RenderUnit {
let cube = stage.draw_unit(&RenderUnit {
vertex_data: VertexData::new_native(vertex_data),
vertex_count: vertices.len() as u32,
camera,
..Default::default()
});

let data = stage.read_all_raw().unwrap();
let invocation = VertexInvocation::invoke(cube.inner(), 0, &data);
println!("vertex invocation: {:#?}", invocation);

let atlas: image::DynamicImage = stage.atlas.read().unwrap().atlas_img().into();
let atlas = CpuTexture2d { image: atlas };
let _ = crate::shader::stage_fragment_impl(&atlas, &CpuSampler);

let img = r.render_image().unwrap();
img_diff::assert_img_eq("scene_cube_directional.png", img);
}
Expand Down
Binary file modified crates/renderling/src/linkage/stage-main_fragment_scene.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-stage_fragment.spv
Binary file not shown.
Loading

0 comments on commit e6ec7f9

Please sign in to comment.