This commit is contained in:
lennlouisgeek
2026-06-28 23:29:13 +08:00
parent f74d8e5013
commit eab24fc2bf
2 changed files with 176 additions and 19 deletions

View File

@@ -115,6 +115,7 @@ pub struct BackgroundRenderResources {
hand_image_pipeline: wgpu::RenderPipeline,
glyph_pipeline: wgpu::RenderPipeline,
dot_pipeline: wgpu::RenderPipeline,
hand_membrane_pipeline: wgpu::RenderPipeline,
hand_dot_pipeline: wgpu::RenderPipeline,
hand_image_bind_group: wgpu::BindGroup,
hand_image_texture: texture::Texture,
@@ -122,6 +123,8 @@ pub struct BackgroundRenderResources {
glyph_vertex_buffer: wgpu::Buffer,
glyph_instance_buffer: wgpu::Buffer,
glyph_instances: Vec<GlyphInstance>,
hand_membrane_instance_buffer: wgpu::Buffer,
hand_membrane_instances: Vec<GlyphInstance>,
hand_dot_instance_buffer: wgpu::Buffer,
hand_dot_instances: Vec<GlyphInstance>,
render_options: RenderOptions,
@@ -445,6 +448,8 @@ impl BackgroundRenderResources {
let glyph_pipeline =
create_glyph_pipeline(device, target_format, &shader, &pipeline_layout);
let dot_pipeline = create_dot_pipeline(device, target_format, &shader, &pipeline_layout);
let hand_membrane_pipeline =
create_hand_membrane_pipeline(device, target_format, &shader, &pipeline_layout);
let hand_dot_pipeline =
create_hand_dot_pipeline(device, target_format, &shader, &pipeline_layout);
@@ -474,6 +479,16 @@ impl BackgroundRenderResources {
contents: bytemuck::cast_slice(&glyph_instances),
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
});
let hand_membrane_instances = build_hand_membrane_instances(
hand_image_texture.width as f32,
hand_image_texture.height as f32,
);
let hand_membrane_instance_buffer =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Hand Fingertip Membrane Instance Buffer"),
contents: bytemuck::cast_slice(&hand_membrane_instances),
usage: wgpu::BufferUsages::VERTEX,
});
let hand_dot_instances = build_hand_dot_instances(
rows,
cols,
@@ -500,12 +515,15 @@ impl BackgroundRenderResources {
hand_image_pipeline,
glyph_pipeline,
dot_pipeline,
hand_membrane_pipeline,
hand_dot_pipeline,
hand_image_bind_group,
hand_image_texture,
glyph_vertex_buffer,
glyph_instance_buffer,
glyph_instances,
hand_membrane_instance_buffer,
hand_membrane_instances,
hand_dot_instance_buffer,
hand_dot_instances,
render_options,
@@ -595,7 +613,12 @@ impl BackgroundRenderResources {
fn paint_hand(&self, render_pass: &mut wgpu::RenderPass<'_>, mode: &HandGatewayMode) {
let _range = mode.range.clone();
// Draw the five fingertip dot matrices after hand.png, so they sit on top of the texture.
// First draw the translucent sensor membranes, then draw live pressure beads on their grid.
render_pass.set_pipeline(&self.hand_membrane_pipeline);
render_pass.set_vertex_buffer(0, self.glyph_vertex_buffer.slice(..));
render_pass.set_vertex_buffer(1, self.hand_membrane_instance_buffer.slice(..));
render_pass.draw(0..6, 0..self.hand_membrane_instances.len() as u32);
render_pass.set_pipeline(&self.hand_dot_pipeline);
render_pass.set_vertex_buffer(0, self.glyph_vertex_buffer.slice(..));
render_pass.set_vertex_buffer(1, self.hand_dot_instance_buffer.slice(..));
@@ -867,6 +890,39 @@ fn create_dot_pipeline(
})
}
fn create_hand_membrane_pipeline(
device: &wgpu::Device,
target_format: &wgpu::TextureFormat,
shader: &wgpu::ShaderModule,
layout: &wgpu::PipelineLayout,
) -> wgpu::RenderPipeline {
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Hand Fingertip Sensor Membrane Pipeline"),
layout: Some(layout),
vertex: wgpu::VertexState {
module: shader,
entry_point: Some("vs_hand_membrane"),
compilation_options: Default::default(),
buffers: &[GlyphVertex::desc(), GlyphInstance::desc()],
},
fragment: Some(wgpu::FragmentState {
module: shader,
entry_point: Some("fs_hand_membrane"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format: *target_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
})
}
fn create_hand_dot_pipeline(
device: &wgpu::Device,
target_format: &wgpu::TextureFormat,
@@ -900,6 +956,24 @@ fn create_hand_dot_pipeline(
})
}
fn build_hand_membrane_instances(image_width: f32, image_height: f32) -> Vec<GlyphInstance> {
HAND_TIP_MATRICES
.iter()
.map(|tip| {
let uv_x = tip.center_px[0] / image_width.max(1.0);
let uv_y = tip.center_px[1] / image_height.max(1.0);
let membrane_size = [tip.size_px[0] * 1.62, tip.size_px[1] * 1.56];
GlyphInstance {
// Membrane shaders read xy as hand.png UV.
world_position: [uv_x, uv_y, 0.0, 1.0],
// Store angle and an oversized source-image pixel size for the floating sensor film.
style: [tip.angle_rad, membrane_size[0], membrane_size[1], 0.0],
}
})
.collect()
}
fn build_hand_dot_instances(
rows: u32,
cols: u32,