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},
};
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());

View File

@ -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::<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 {
let params = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: size_of::<Params>() as u64,
size: size_of::<ObjectParams>() 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(&params));
}
}
@ -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, &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.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, &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_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint16);
pass.draw_indexed(0..self.index_count, 0, 0..1);

View File

@ -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<uniform> params: Params;
@group(0) @binding(0) var<uniform> scene_params: SceneParams;
@group(1) @binding(0) var<uniform> 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;
}