169 lines
3.9 KiB
Rust
169 lines
3.9 KiB
Rust
use std::mem;
|
|
|
|
use bytemuck::{bytes_of, cast_slice, Pod, Zeroable};
|
|
use glam::{Vec3, Vec4};
|
|
use wgpu::util::DeviceExt as _;
|
|
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
struct Vertex {
|
|
pub position: [f32; 3],
|
|
pub normal: [f32; 3],
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Pod, Zeroable)]
|
|
struct PushConsts {
|
|
pub color: [f32; 4],
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub struct Attrs {
|
|
pub color: Vec4,
|
|
}
|
|
|
|
impl Attrs {
|
|
fn consts(&self) -> PushConsts {
|
|
PushConsts {
|
|
color: self.color.to_array(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Mesh {
|
|
consts: PushConsts,
|
|
npoints: u32,
|
|
buf: wgpu::Buffer,
|
|
}
|
|
|
|
impl Mesh {
|
|
pub fn new_list(device: &wgpu::Device, attrs: Attrs, tris: Vec<(Vec3, Vec3, Vec3)>) -> Self {
|
|
let data: Vec<Vertex> = tris
|
|
.into_iter()
|
|
.flat_map(|(a, b, c)| {
|
|
let n = (b - a).cross(c - a).normalize();
|
|
[
|
|
Vertex {
|
|
position: a.into(),
|
|
normal: n.into(),
|
|
},
|
|
Vertex {
|
|
position: b.into(),
|
|
normal: n.into(),
|
|
},
|
|
Vertex {
|
|
position: c.into(),
|
|
normal: n.into(),
|
|
},
|
|
]
|
|
})
|
|
.collect();
|
|
let buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
label: Some("Mesh Vertex Buffer"),
|
|
contents: cast_slice(&data),
|
|
usage: wgpu::BufferUsages::VERTEX,
|
|
});
|
|
Mesh {
|
|
consts: attrs.consts(),
|
|
npoints: data.len() as u32,
|
|
buf,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Renderer {
|
|
pipeline: wgpu::RenderPipeline,
|
|
}
|
|
|
|
static SHADER: &'static str = include_str!("mesh.wgsl");
|
|
|
|
impl Renderer {
|
|
pub fn new(
|
|
device: &wgpu::Device,
|
|
cam_layout: &wgpu::BindGroupLayout,
|
|
target_format: wgpu::TextureFormat,
|
|
depth_stencil: Option<wgpu::DepthStencilState>,
|
|
multisample: wgpu::MultisampleState,
|
|
) -> Renderer {
|
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
label: Some("Mesh Shader"),
|
|
source: wgpu::ShaderSource::Wgsl(SHADER.into()),
|
|
});
|
|
|
|
let consts_range = wgpu::PushConstantRange {
|
|
stages: wgpu::ShaderStages::VERTEX,
|
|
range: 0..mem::size_of::<PushConsts>() as u32,
|
|
};
|
|
|
|
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: Some("Mesh RenderPipelineLayout"),
|
|
bind_group_layouts: &[cam_layout],
|
|
push_constant_ranges: &[consts_range],
|
|
});
|
|
|
|
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
label: Some("Mesh RenderPipeline"),
|
|
layout: Some(&layout),
|
|
vertex: wgpu::VertexState {
|
|
module: &shader,
|
|
entry_point: "vs_main",
|
|
buffers: &[wgpu::VertexBufferLayout {
|
|
array_stride: mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
|
step_mode: wgpu::VertexStepMode::Vertex,
|
|
attributes: &[
|
|
wgpu::VertexAttribute {
|
|
offset: mem::offset_of!(Vertex, position) as u64,
|
|
shader_location: 0,
|
|
format: wgpu::VertexFormat::Float32x3,
|
|
},
|
|
wgpu::VertexAttribute {
|
|
offset: mem::offset_of!(Vertex, normal) as u64,
|
|
shader_location: 1,
|
|
format: wgpu::VertexFormat::Float32x3,
|
|
},
|
|
],
|
|
}],
|
|
compilation_options: Default::default(),
|
|
},
|
|
fragment: Some(wgpu::FragmentState {
|
|
module: &shader,
|
|
entry_point: "fs_main",
|
|
targets: &[Some(wgpu::ColorTargetState {
|
|
format: target_format,
|
|
blend: Some(wgpu::BlendState {
|
|
color: wgpu::BlendComponent::OVER,
|
|
alpha: wgpu::BlendComponent::OVER,
|
|
}),
|
|
write_mask: wgpu::ColorWrites::ALL,
|
|
})],
|
|
compilation_options: Default::default(),
|
|
}),
|
|
primitive: wgpu::PrimitiveState {
|
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
|
..Default::default()
|
|
},
|
|
depth_stencil,
|
|
multisample,
|
|
multiview: None,
|
|
cache: None,
|
|
});
|
|
|
|
Renderer { pipeline }
|
|
}
|
|
|
|
pub fn render<'a>(
|
|
&self,
|
|
pass: &mut wgpu::RenderPass,
|
|
cam_bind: &wgpu::BindGroup,
|
|
meshes: impl Iterator<Item = &'a Mesh>,
|
|
) {
|
|
pass.set_pipeline(&self.pipeline);
|
|
pass.set_bind_group(0, cam_bind, &[]);
|
|
for mesh in meshes {
|
|
pass.set_push_constants(wgpu::ShaderStages::VERTEX, 0, bytes_of(&mesh.consts));
|
|
pass.set_vertex_buffer(0, mesh.buf.slice(..));
|
|
pass.draw(0..mesh.npoints, 0..1);
|
|
}
|
|
}
|
|
}
|