From be3ef2e4bdafe52c481d4d62f43128dd39605b3a Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 19 Oct 2026 03:03:08 +0300 Subject: [PATCH] separate global (light) and per-object (position) parameters --- src/lib.rs | 55 ++++++++++++++++++++++++-------------------- src/render/mesh.rs | 48 +++++++++++++++++++++++++++++++------- src/render/mesh.wgsl | 19 +++++++++------ 3 files changed, 82 insertions(+), 40 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 643b3ad..f443750 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use std::{ f32::consts::{FRAC_PI_2, PI}, }; -use glam::{Affine3A, FloatExt, Mat4, Quat, UVec2, Vec3, Vec4, vec3, vec4}; +use glam::{FloatExt, Mat4, Quat, UVec2, Vec3, Vec4, vec3, vec4}; use crate::render::mesh::GpuParams; @@ -188,37 +188,42 @@ impl Core { .to_mat4(); let view = Mat4::from_mat3(camera::rotation(-args.cam_yaw, -args.cam_pitch)); let light = vec3(0.7, 0.5, 1.0).normalize(); - let set_params = |target: &GpuParams, color, tfm| { - target.set( - &self.queue, - render::mesh::Params { - mvp: proj * view * tfm, - light, - _zero: 0., - color: srgba_to_linear(color), - }, - ); - }; + + self.mesh_pipeline.set_params( + &self.queue, + render::mesh::SceneParams { + projection: proj * view, + light, + _zero: 0., + }, + ); let turn_teeth = self.t; - let bevel_turns = turn_teeth / self.bevel_gear_desc.teeth as f32; + let bevel_turns = -turn_teeth / self.bevel_gear_desc.teeth as f32; let crown_skip_teeth = self.crown_gear_desc.pitch_radius.floor(); let crown_turns = (turn_teeth.fract_gl() + crown_skip_teeth) / (2. * self.crown_gear_desc.pitch_radius); - set_params( - &self.params_gear, - vec4(0.2, 0.8, 0.1, 1.0), - Affine3A::IDENTITY, + self.params_gear.set( + &self.queue, + render::mesh::ObjectParams { + transform: Mat4::from_rotation_translation( + Quat::from_rotation_z(2. * PI * bevel_turns), + Vec3::ZERO, + ), + color: srgba_to_linear(vec4(0.2, 0.8, 0.1, 1.0)), + }, ); - set_params( - &self.params_cutter, - vec4(0.8, 0.2, 0.1, 1.0), - Affine3A::from_rotation_translation( - Quat::from_rotation_y(FRAC_PI_2 + self.bevel_gear_desc.cone_halfangle) - * Quat::from_rotation_z(2. * PI * crown_turns), - vec3(0., 0., self.bevel_gear_desc.pitch_distance()), - ), + self.params_cutter.set( + &self.queue, + render::mesh::ObjectParams { + transform: Mat4::from_rotation_translation( + Quat::from_rotation_y(FRAC_PI_2 + self.bevel_gear_desc.cone_halfangle) + * Quat::from_rotation_z(2. * PI * crown_turns), + vec3(0., 0., self.bevel_gear_desc.pitch_distance()), + ), + color: srgba_to_linear(vec4(0.8, 0.2, 0.1, 1.0)), + }, ); let view = output.create_view(&wgpu::TextureViewDescriptor::default()); diff --git a/src/render/mesh.rs b/src/render/mesh.rs index 9620fc9..41bba08 100644 --- a/src/render/mesh.rs +++ b/src/render/mesh.rs @@ -19,15 +19,23 @@ pub struct Vertex { #[derive(Debug, Clone, Copy, Zeroable, Pod)] #[repr(C)] -pub struct Params { - pub mvp: Mat4, +pub struct SceneParams { + pub projection: Mat4, pub light: Vec3, pub _zero: f32, +} + +#[derive(Debug, Clone, Copy, Zeroable, Pod)] +#[repr(C)] +pub struct ObjectParams { + pub transform: Mat4, pub color: Vec4, } pub struct Pipeline { pipeline: wgpu::RenderPipeline, + params: wgpu::Buffer, + bindings: wgpu::BindGroup, } pub struct GpuMesh { @@ -153,7 +161,29 @@ impl Pipeline { multiview: None, cache: None, }); - Self { pipeline } + let params = device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: size_of::() as u64, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &pipeline.get_bind_group_layout(0), + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: params.as_entire_binding(), + }], + }); + Self { + params, + bindings, + pipeline, + } + } + + pub fn set_params(&self, queue: &wgpu::Queue, params: SceneParams) { + queue.write_buffer(&self.params, 0, bytes_of(¶ms)); } } @@ -161,13 +191,13 @@ impl GpuParams { pub fn new(device: &wgpu::Device, pipeline: &Pipeline) -> Self { let params = device.create_buffer(&wgpu::BufferDescriptor { label: None, - size: size_of::() as u64, + size: size_of::() as u64, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor { label: None, - layout: &pipeline.pipeline.get_bind_group_layout(0), + layout: &pipeline.pipeline.get_bind_group_layout(1), entries: &[wgpu::BindGroupEntry { binding: 0, resource: params.as_entire_binding(), @@ -176,7 +206,7 @@ impl GpuParams { Self { params, bindings } } - pub fn set(&self, queue: &wgpu::Queue, params: Params) { + pub fn set(&self, queue: &wgpu::Queue, params: ObjectParams) { queue.write_buffer(&self.params, 0, bytes_of(¶ms)); } } @@ -184,7 +214,8 @@ impl GpuParams { impl GpuMesh { pub fn render(&self, pass: &mut wgpu::RenderPass, pipeline: &Pipeline, params: &GpuParams) { pass.set_pipeline(&pipeline.pipeline); - pass.set_bind_group(0, ¶ms.bindings, &[]); + pass.set_bind_group(0, &pipeline.bindings, &[]); + pass.set_bind_group(1, ¶ms.bindings, &[]); pass.set_vertex_buffer(0, self.vertices.slice(..)); pass.draw(0..self.vertex_count, 0..1); } @@ -193,7 +224,8 @@ impl GpuMesh { impl GpuMeshIndexed { pub fn render(&self, pass: &mut wgpu::RenderPass, pipeline: &Pipeline, params: &GpuParams) { pass.set_pipeline(&pipeline.pipeline); - pass.set_bind_group(0, ¶ms.bindings, &[]); + pass.set_bind_group(0, &pipeline.bindings, &[]); + pass.set_bind_group(1, ¶ms.bindings, &[]); pass.set_vertex_buffer(0, self.vertices.slice(..)); pass.set_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint16); pass.draw_indexed(0..self.index_count, 0, 0..1); diff --git a/src/render/mesh.wgsl b/src/render/mesh.wgsl index 35ea427..c7e25a2 100644 --- a/src/render/mesh.wgsl +++ b/src/render/mesh.wgsl @@ -1,7 +1,11 @@ -struct Params { - mvp: mat4x4f, +struct SceneParams { + projection: mat4x4f, light: vec3f, _zero: f32, +} + +struct ObjectParams { + transform: mat4x4f, color: vec4f, } @@ -15,20 +19,21 @@ struct Varying { @location(0) normal: vec3f, } -@group(0) @binding(0) var params: Params; +@group(0) @binding(0) var scene_params: SceneParams; +@group(1) @binding(0) var object_params: ObjectParams; @vertex fn on_vertex(in: Vertex) -> Varying { - let position = params.mvp * vec4f(in.position, 1.0); - let normal = in.normal; + let position = scene_params.projection * object_params.transform * vec4f(in.position, 1.0); + let normal = normalize((object_params.transform * vec4(in.normal, 0.0)).xyz); return Varying(position, normal); } @fragment fn on_fragment(in: Varying) -> @location(0) vec4f { let normal = normalize(in.normal); - let light = dot(params.light, normal); + let light = dot(scene_params.light, normal); let u = 0.5 + 0.5 * light; - let color = vec4f(u * params.color.xyz, params.color.w); + let color = vec4f(u * object_params.color.xyz, object_params.color.w); return color; }