separate global (light) and per-object (position) parameters

This commit is contained in:
numzero 2026-10-19 03:03:08 +03:00
parent 82638f7ad3
commit be3ef2e4bd
3 changed files with 82 additions and 40 deletions

View File

@ -3,7 +3,7 @@ use std::{
f32::consts::{FRAC_PI_2, PI}, 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; use crate::render::mesh::GpuParams;
@ -188,37 +188,42 @@ impl Core {
.to_mat4(); .to_mat4();
let view = Mat4::from_mat3(camera::rotation(-args.cam_yaw, -args.cam_pitch)); let view = Mat4::from_mat3(camera::rotation(-args.cam_yaw, -args.cam_pitch));
let light = vec3(0.7, 0.5, 1.0).normalize(); let light = vec3(0.7, 0.5, 1.0).normalize();
let set_params = |target: &GpuParams, color, tfm| {
target.set( self.mesh_pipeline.set_params(
&self.queue, &self.queue,
render::mesh::Params { render::mesh::SceneParams {
mvp: proj * view * tfm, projection: proj * view,
light, light,
_zero: 0., _zero: 0.,
color: srgba_to_linear(color), },
}, );
);
};
let turn_teeth = self.t; 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_skip_teeth = self.crown_gear_desc.pitch_radius.floor();
let crown_turns = let crown_turns =
(turn_teeth.fract_gl() + crown_skip_teeth) / (2. * self.crown_gear_desc.pitch_radius); (turn_teeth.fract_gl() + crown_skip_teeth) / (2. * self.crown_gear_desc.pitch_radius);
set_params( self.params_gear.set(
&self.params_gear, &self.queue,
vec4(0.2, 0.8, 0.1, 1.0), render::mesh::ObjectParams {
Affine3A::IDENTITY, 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.set(
&self.params_cutter, &self.queue,
vec4(0.8, 0.2, 0.1, 1.0), render::mesh::ObjectParams {
Affine3A::from_rotation_translation( transform: Mat4::from_rotation_translation(
Quat::from_rotation_y(FRAC_PI_2 + self.bevel_gear_desc.cone_halfangle) Quat::from_rotation_y(FRAC_PI_2 + self.bevel_gear_desc.cone_halfangle)
* Quat::from_rotation_z(2. * PI * crown_turns), * Quat::from_rotation_z(2. * PI * crown_turns),
vec3(0., 0., self.bevel_gear_desc.pitch_distance()), 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()); let view = output.create_view(&wgpu::TextureViewDescriptor::default());

View File

@ -19,15 +19,23 @@ pub struct Vertex {
#[derive(Debug, Clone, Copy, Zeroable, Pod)] #[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)] #[repr(C)]
pub struct Params { pub struct SceneParams {
pub mvp: Mat4, pub projection: Mat4,
pub light: Vec3, pub light: Vec3,
pub _zero: f32, pub _zero: f32,
}
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)]
pub struct ObjectParams {
pub transform: Mat4,
pub color: Vec4, pub color: Vec4,
} }
pub struct Pipeline { pub struct Pipeline {
pipeline: wgpu::RenderPipeline, pipeline: wgpu::RenderPipeline,
params: wgpu::Buffer,
bindings: wgpu::BindGroup,
} }
pub struct GpuMesh { pub struct GpuMesh {
@ -153,7 +161,29 @@ impl Pipeline {
multiview: None, multiview: None,
cache: None, cache: None,
}); });
Self { pipeline } let params = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: size_of::<SceneParams>() 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(&params));
} }
} }
@ -161,13 +191,13 @@ impl GpuParams {
pub fn new(device: &wgpu::Device, pipeline: &Pipeline) -> Self { pub fn new(device: &wgpu::Device, pipeline: &Pipeline) -> Self {
let params = device.create_buffer(&wgpu::BufferDescriptor { let params = device.create_buffer(&wgpu::BufferDescriptor {
label: None, label: None,
size: size_of::<Params>() as u64, size: size_of::<ObjectParams>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor { let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None, label: None,
layout: &pipeline.pipeline.get_bind_group_layout(0), layout: &pipeline.pipeline.get_bind_group_layout(1),
entries: &[wgpu::BindGroupEntry { entries: &[wgpu::BindGroupEntry {
binding: 0, binding: 0,
resource: params.as_entire_binding(), resource: params.as_entire_binding(),
@ -176,7 +206,7 @@ impl GpuParams {
Self { params, bindings } 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(&params)); queue.write_buffer(&self.params, 0, bytes_of(&params));
} }
} }
@ -184,7 +214,8 @@ impl GpuParams {
impl GpuMesh { impl GpuMesh {
pub fn render(&self, pass: &mut wgpu::RenderPass, pipeline: &Pipeline, params: &GpuParams) { pub fn render(&self, pass: &mut wgpu::RenderPass, pipeline: &Pipeline, params: &GpuParams) {
pass.set_pipeline(&pipeline.pipeline); pass.set_pipeline(&pipeline.pipeline);
pass.set_bind_group(0, &params.bindings, &[]); pass.set_bind_group(0, &pipeline.bindings, &[]);
pass.set_bind_group(1, &params.bindings, &[]);
pass.set_vertex_buffer(0, self.vertices.slice(..)); pass.set_vertex_buffer(0, self.vertices.slice(..));
pass.draw(0..self.vertex_count, 0..1); pass.draw(0..self.vertex_count, 0..1);
} }
@ -193,7 +224,8 @@ impl GpuMesh {
impl GpuMeshIndexed { impl GpuMeshIndexed {
pub fn render(&self, pass: &mut wgpu::RenderPass, pipeline: &Pipeline, params: &GpuParams) { pub fn render(&self, pass: &mut wgpu::RenderPass, pipeline: &Pipeline, params: &GpuParams) {
pass.set_pipeline(&pipeline.pipeline); pass.set_pipeline(&pipeline.pipeline);
pass.set_bind_group(0, &params.bindings, &[]); pass.set_bind_group(0, &pipeline.bindings, &[]);
pass.set_bind_group(1, &params.bindings, &[]);
pass.set_vertex_buffer(0, self.vertices.slice(..)); pass.set_vertex_buffer(0, self.vertices.slice(..));
pass.set_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint16); pass.set_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint16);
pass.draw_indexed(0..self.index_count, 0, 0..1); pass.draw_indexed(0..self.index_count, 0, 0..1);

View File

@ -1,7 +1,11 @@
struct Params { struct SceneParams {
mvp: mat4x4f, projection: mat4x4f,
light: vec3f, light: vec3f,
_zero: f32, _zero: f32,
}
struct ObjectParams {
transform: mat4x4f,
color: vec4f, color: vec4f,
} }
@ -15,20 +19,21 @@ struct Varying {
@location(0) normal: vec3f, @location(0) normal: vec3f,
} }
@group(0) @binding(0) var<uniform> params: Params; @group(0) @binding(0) var<uniform> scene_params: SceneParams;
@group(1) @binding(0) var<uniform> object_params: ObjectParams;
@vertex @vertex
fn on_vertex(in: Vertex) -> Varying { fn on_vertex(in: Vertex) -> Varying {
let position = params.mvp * vec4f(in.position, 1.0); let position = scene_params.projection * object_params.transform * vec4f(in.position, 1.0);
let normal = in.normal; let normal = normalize((object_params.transform * vec4(in.normal, 0.0)).xyz);
return Varying(position, normal); return Varying(position, normal);
} }
@fragment @fragment
fn on_fragment(in: Varying) -> @location(0) vec4f { fn on_fragment(in: Varying) -> @location(0) vec4f {
let normal = normalize(in.normal); 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 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; return color;
} }