From 5a6b10965de4b6fb530df846ec76a92b0722b8c4 Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 24 Nov 2025 17:29:08 +0300 Subject: [PATCH] show spheres --- src/lib.rs | 29 ++++++++ src/render/faces.rs | 161 ++++++++++++++++++++++++++++++++++++++++++++ src/render/mod.rs | 1 + 3 files changed, 191 insertions(+) create mode 100644 src/render/faces.rs diff --git a/src/lib.rs b/src/lib.rs index ce55aa2..f2122d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ pub struct Core { surface: wgpu::Surface<'static>, pipeline: Pipeline, + mesh_pipe: render::faces::Pipeline, tripod: Mesh, } @@ -130,6 +131,7 @@ impl Core { } = gpu; let pipeline = Pipeline::new(&device, OUTPUT_FORMAT); + let mesh_pipe = render::faces::Pipeline::new(&device, OUTPUT_FORMAT); let tripod = new_tripod(&device); queue.submit([]); // flush buffer updates @@ -139,6 +141,7 @@ impl Core { surface, pipeline, tripod, + mesh_pipe, } } @@ -161,6 +164,12 @@ impl Core { m: perspective * camera.transform(), }, ); + self.mesh_pipe.set_look( + &self.queue, + render::faces::LookParams { + m: perspective * camera.transform(), + }, + ); self.queue.submit([]); // flush buffer updates let view = output.create_view(&wgpu::TextureViewDescriptor::default()); @@ -223,6 +232,26 @@ impl Core { sphere(vec3(0.1, 0.3, 0.1)), ], }; + if args.show_shapes { + let mut meshes = Vec::new(); + for obj in &scene.objects { + let mesh = shape::sphere((obj.radius * 15.) as usize + 7); + let obj_mesh = render::faces::Mesh::new( + &self.device, + &mesh + .vertices + .iter() + .map(|v| render::faces::Vertex { + pos: obj.position + obj.radius * v, + color: 0.5 * (v + 1.), + }) + .collect::>(), + bytemuck::cast_slice(&mesh.indices), + ); + meshes.push(obj_mesh); + } + self.mesh_pipe.render(&mut pass, &meshes); + } let mut prng = rand_pcg::Pcg64::new(42, 0); let source_rays: Vec = (0..10240).map(|_| source.make_ray(&mut prng)).collect(); diff --git a/src/render/faces.rs b/src/render/faces.rs new file mode 100644 index 0000000..1776a39 --- /dev/null +++ b/src/render/faces.rs @@ -0,0 +1,161 @@ +use std::mem::offset_of; + +use bytemuck::{Pod, Zeroable, bytes_of, cast_slice}; +use glam::{Mat4, Vec3}; +use wgpu::util::DeviceExt as _; + +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct LookParams { + pub m: Mat4, +} + +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct Vertex { + pub pos: Vec3, + pub color: Vec3, +} + +impl Vertex { + pub fn new(pos: Vec3, color: Vec3) -> Self { + Self { pos, color } + } +} + +pub struct Mesh { + vertex_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, + index_count: u32, +} + +impl Mesh { + pub fn new(device: &wgpu::Device, vertices: &[Vertex], indices: &[u16]) -> Self { + if vertices.len() >= 1 << 16 { + panic!("too many vertices"); + } + for index in indices { + if *index as usize >= vertices.len() { + panic!( + "vertex index out of bounds: {index} out of {}", + vertices.len() + ); + } + } + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + usage: wgpu::BufferUsages::VERTEX, + contents: cast_slice(vertices), + }); + let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + usage: wgpu::BufferUsages::INDEX, + contents: cast_slice(indices), + }); + Self { + vertex_buffer, + index_buffer, + index_count: indices.len().try_into().expect("too many indices"), + } + } +} + +pub struct Pipeline { + look_buf: wgpu::Buffer, + bindings: wgpu::BindGroup, + pipeline: wgpu::RenderPipeline, +} + +impl Pipeline { + pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { + let look_buf = 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 shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::Wgsl(super::SIMPLE_SHADER.into()), + }); + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: None, + vertex: wgpu::VertexState { + module: &shader, + entry_point: None, + compilation_options: wgpu::PipelineCompilationOptions::default(), + buffers: &[wgpu::VertexBufferLayout { + array_stride: size_of::() as u64, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + wgpu::VertexAttribute { + shader_location: 0, + offset: offset_of!(Vertex, pos) as u64, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + shader_location: 1, + offset: offset_of!(Vertex, color) as u64, + format: wgpu::VertexFormat::Float32x3, + }, + ], + }], + }, + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: None, + compilation_options: wgpu::PipelineCompilationOptions::default(), + targets: &[Some(wgpu::ColorTargetState { + format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + multiview: None, + cache: None, + }); + let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &pipeline.get_bind_group_layout(0), + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: look_buf.as_entire_binding(), + }], + }); + Self { + look_buf, + bindings, + pipeline, + } + } + + pub fn set_look(&self, queue: &wgpu::Queue, look: LookParams) { + queue.write_buffer(&self.look_buf, 0, bytes_of(&look)); + } + + pub fn render<'a>( + &self, + pass: &mut wgpu::RenderPass, + meshes: impl IntoIterator, + ) { + pass.set_pipeline(&self.pipeline); + pass.set_bind_group(0, &self.bindings, &[]); + for mesh in meshes { + pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + pass.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint16); + pass.draw_indexed(0..mesh.index_count, 0, 0..1); + } + } +} diff --git a/src/render/mod.rs b/src/render/mod.rs index 249b8bb..291e015 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,3 +1,4 @@ +pub mod faces; pub mod lines; static SIMPLE_SHADER: &str = include_str!("simple.wgsl");