From f6623be63a4e3e08aaa6239e51e0b47e57b86171 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 11 Dec 2023 23:36:24 -0800 Subject: [PATCH] Support front face configuration for meshes --- blade-render/code/fill-gbuf.wgsl | 4 ++-- blade-render/code/ray-trace.wgsl | 6 ++---- blade-render/src/model/mod.rs | 23 +++++++++++++++++++++-- blade-render/src/render/mod.rs | 4 ++-- docs/CHANGELOG.md | 1 + examples/init/main.rs | 9 +++------ examples/scene/main.rs | 2 ++ src/config.rs | 14 ++++++++++++++ src/lib.rs | 4 ++++ 9 files changed, 51 insertions(+), 16 deletions(-) diff --git a/blade-render/code/fill-gbuf.wgsl b/blade-render/code/fill-gbuf.wgsl index 0f143bb7..b0ca69e0 100644 --- a/blade-render/code/fill-gbuf.wgsl +++ b/blade-render/code/fill-gbuf.wgsl @@ -30,9 +30,9 @@ var sampler_nearest: sampler; struct HitEntry { index_buf: u32, vertex_buf: u32, + winding: f32, // packed quaternion geometry_to_world_rotation: u32, - pad: u32, geometry_to_object: mat4x3, prev_object_to_world: mat4x3, base_color_texture: u32, @@ -105,7 +105,7 @@ fn main(@builtin(global_invocation_id) global_id: vec3) { let positions = intersection.object_to_world * mat3x4( vec4(positions_object[0], 1.0), vec4(positions_object[1], 1.0), vec4(positions_object[2], 1.0) ); - flat_normal = normalize(cross(positions[1].xyz - positions[0].xyz, positions[2].xyz - positions[0].xyz)); + flat_normal = entry.winding * normalize(cross(positions[1].xyz - positions[0].xyz, positions[2].xyz - positions[0].xyz)); let barycentrics = vec3(1.0 - intersection.barycentrics.x - intersection.barycentrics.y, intersection.barycentrics); let position_object = vec4(positions_object * barycentrics, 1.0); diff --git a/blade-render/code/ray-trace.wgsl b/blade-render/code/ray-trace.wgsl index 47ebee45..743eb03c 100644 --- a/blade-render/code/ray-trace.wgsl +++ b/blade-render/code/ray-trace.wgsl @@ -297,14 +297,12 @@ fn estimate_target_score_with_occlusion( fn evaluate_sample(ls: LightSample, surface: Surface, start_pos: vec3, debug_len: f32) -> f32 { let dir = map_equirect_uv_to_dir(ls.uv); - if (dot(dir, surface.flat_normal) <= 0.0) - { + if (dot(dir, surface.flat_normal) <= 0.0) { return 0.0; } let brdf = evaluate_brdf(surface, dir); - if (brdf <= 0.0) - { + if (brdf <= 0.0) { return 0.0; } diff --git a/blade-render/src/model/mod.rs b/blade-render/src/model/mod.rs index 96e166a2..1c871521 100644 --- a/blade-render/src/model/mod.rs +++ b/blade-render/src/model/mod.rs @@ -50,6 +50,7 @@ pub struct Material { pub struct Model { pub name: String, + pub winding: f32, pub geometries: Vec, pub materials: Vec, pub vertex_buffer: blade_graphics::Buffer, @@ -163,6 +164,7 @@ impl FlattenedGeometry { #[derive(blade_macros::Flat)] pub struct CookedModel<'a> { name: &'a [u8], + winding: f32, materials: Vec>, geometries: Vec>, } @@ -272,14 +274,26 @@ impl CookedModel<'_> { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum FrontFace { + Clockwise, + CounterClockwise, +} +impl Default for FrontFace { + fn default() -> Self { + Self::CounterClockwise + } +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct Meta { pub generate_tangents: bool, + pub front_face: FrontFace, } impl fmt::Display for Meta { fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - Ok(()) + Ok(()) //TODO } } @@ -496,6 +510,10 @@ impl blade_asset::Baker for Baker { let mut sources = slab::Slab::new(); let mut model = CookedModel { name: &[], + winding: match meta.front_face { + FrontFace::Clockwise => -1.0, + FrontFace::CounterClockwise => 1.0, + }, materials: Vec::new(), geometries: Vec::new(), }; @@ -756,6 +774,7 @@ impl blade_asset::Baker for Baker { Model { name: String::from_utf8_lossy(model.name).into_owned(), + winding: model.winding, geometries, materials, vertex_buffer, diff --git a/blade-render/src/render/mod.rs b/blade-render/src/render/mod.rs index 83efda76..1c5cfec7 100644 --- a/blade-render/src/render/mod.rs +++ b/blade-render/src/render/mod.rs @@ -463,8 +463,8 @@ struct PostProcData { struct HitEntry { index_buf: u32, vertex_buf: u32, + winding: f32, geometry_to_world_rotation: [i8; 4], - unused: u32, //Note: it's technically `mat4x3` on WGSL side, // but it's aligned and sized the same way as `mat4`. geometry_to_object: mint::ColumnMatrix4, @@ -913,8 +913,8 @@ impl Renderer { vertex_buf: self .vertex_buffers .alloc(model.vertex_buffer.at(vertex_offset)), + winding: model.winding, geometry_to_world_rotation, - unused: 0, geometry_to_object: mint::ColumnMatrix4::from(mint::RowMatrix4 { x: geometry.transform.x, y: geometry.transform.y, diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8864c27b..aa68d0fd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -3,6 +3,7 @@ Changelog for Blade ## blade-0.2 (TBD) - high-level engine - support object motion +- support clockwise mesh winding ## blade-graphics-0.3, blade-render-0.2 (17 Nov 2023) - tangent space generation diff --git a/examples/init/main.rs b/examples/init/main.rs index 0ddec649..5d6b713c 100644 --- a/examples/init/main.rs +++ b/examples/init/main.rs @@ -179,12 +179,9 @@ fn main() { environment_map = Some(texture); } else if arg.ends_with(".gltf") { println!("\tmodels += {}", arg); - let (model, model_task) = asset_hub.models.load( - arg, - blade_render::model::Meta { - generate_tangents: false, - }, - ); + let (model, model_task) = asset_hub + .models + .load(arg, blade_render::model::Meta::default()); load_finish.depend_on(model_task); _object = Some(blade_render::Object::from(model)); } else { diff --git a/examples/scene/main.rs b/examples/scene/main.rs index 68401777..4d57866a 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -339,6 +339,7 @@ impl Example { parent.join(&config_object.path), blade_render::model::Meta { generate_tangents: true, + ..Default::default() }, ); load_finish.depend_on(model_task); @@ -983,6 +984,7 @@ impl Example { file_path, blade_render::model::Meta { generate_tangents: true, + ..Default::default() }, ); self.scene_load_task = Some(model_task.clone()); diff --git a/src/config.rs b/src/config.rs index 204fc5d9..55b964da 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,14 @@ +#[derive(serde::Deserialize)] +pub enum FrontFace { + Cw, + Ccw, +} +impl Default for FrontFace { + fn default() -> Self { + Self::Ccw + } +} + fn default_vec() -> mint::Vector3 { [0.0; 3].into() } @@ -8,6 +19,8 @@ fn default_scale() -> f32 { #[derive(serde::Deserialize)] pub struct Visual { pub model: String, + #[serde(default)] + pub front_face: FrontFace, #[serde(default = "default_vec")] pub pos: mint::Vector3, #[serde(default = "default_vec")] @@ -19,6 +32,7 @@ impl Default for Visual { fn default() -> Self { Self { model: String::new(), + front_face: FrontFace::default(), pos: default_vec(), rot: default_vec(), scale: default_scale(), diff --git a/src/lib.rs b/src/lib.rs index b76aa8ab..7ca9e986 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -622,6 +622,10 @@ impl Engine { format!("{}/{}", self.data_path, visual.model), blade_render::model::Meta { generate_tangents: true, + front_face: match visual.front_face { + config::FrontFace::Cw => blade_render::model::FrontFace::Clockwise, + config::FrontFace::Ccw => blade_render::model::FrontFace::CounterClockwise, + }, }, ); visuals.push(Visual {