rendering, physics, player and camera WIP
This commit is contained in:
414
src/mesh.rs
Normal file
414
src/mesh.rs
Normal file
@@ -0,0 +1,414 @@
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use glam::{Mat4, Vec3};
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::utility::transform::Transform;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
pub struct Vertex
|
||||
{
|
||||
pub position: [f32; 3],
|
||||
pub normal: [f32; 3],
|
||||
pub uv: [f32; 2],
|
||||
}
|
||||
|
||||
impl Vertex
|
||||
{
|
||||
pub fn desc() -> wgpu::VertexBufferLayout<'static>
|
||||
{
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
attributes: &[
|
||||
wgpu::VertexAttribute {
|
||||
offset: 0,
|
||||
shader_location: 0,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
|
||||
shader_location: 1,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: (std::mem::size_of::<[f32; 3]>() * 2) as wgpu::BufferAddress,
|
||||
shader_location: 2,
|
||||
format: wgpu::VertexFormat::Float32x2,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mesh
|
||||
{
|
||||
pub vertex_buffer: wgpu::Buffer,
|
||||
pub index_buffer: wgpu::Buffer,
|
||||
pub num_indices: u32,
|
||||
}
|
||||
|
||||
impl Mesh
|
||||
{
|
||||
pub fn new(device: &wgpu::Device, vertices: &[Vertex], indices: &[u32]) -> Self
|
||||
{
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
contents: bytemuck::cast_slice(vertices),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
});
|
||||
|
||||
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: bytemuck::cast_slice(indices),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
});
|
||||
|
||||
Self {
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
num_indices: indices.len() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_cube_mesh(device: &wgpu::Device) -> Mesh
|
||||
{
|
||||
let vertices = vec![
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, 0.5],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, 0.5],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, 0.5],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, 0.5],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, 0.5],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, -0.5],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, -0.5],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, 0.5],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, -0.5],
|
||||
normal: [0.0, 0.0, -1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, -0.5],
|
||||
normal: [0.0, 0.0, -1.0],
|
||||
uv: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, -0.5],
|
||||
normal: [0.0, 0.0, -1.0],
|
||||
uv: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, -0.5],
|
||||
normal: [0.0, 0.0, -1.0],
|
||||
uv: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, -0.5],
|
||||
normal: [-1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, 0.5],
|
||||
normal: [-1.0, 0.0, 0.0],
|
||||
uv: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, 0.5],
|
||||
normal: [-1.0, 0.0, 0.0],
|
||||
uv: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, -0.5],
|
||||
normal: [-1.0, 0.0, 0.0],
|
||||
uv: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, 0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, 0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, -0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, -0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, -0.5],
|
||||
normal: [0.0, -1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, -0.5],
|
||||
normal: [0.0, -1.0, 0.0],
|
||||
uv: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, 0.5],
|
||||
normal: [0.0, -1.0, 0.0],
|
||||
uv: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, 0.5],
|
||||
normal: [0.0, -1.0, 0.0],
|
||||
uv: [0.0, 1.0],
|
||||
},
|
||||
];
|
||||
|
||||
let indices = vec![
|
||||
0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 10, 11, 8, 12, 13, 14, 14, 15, 12, 16,
|
||||
17, 18, 18, 19, 16, 20, 21, 22, 22, 23, 20,
|
||||
];
|
||||
|
||||
Mesh::new(device, &vertices, &indices)
|
||||
}
|
||||
|
||||
pub fn create_plane_mesh(
|
||||
device: &wgpu::Device,
|
||||
width: f32,
|
||||
height: f32,
|
||||
subdivisions_x: u32,
|
||||
subdivisions_y: u32,
|
||||
) -> Mesh
|
||||
{
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
|
||||
for y in 0..=subdivisions_y
|
||||
{
|
||||
for x in 0..=subdivisions_x
|
||||
{
|
||||
let fx = x as f32 / subdivisions_x as f32;
|
||||
let fy = y as f32 / subdivisions_y as f32;
|
||||
|
||||
let px = (fx - 0.5) * width;
|
||||
let py = 0.0;
|
||||
let pz = (fy - 0.5) * height;
|
||||
|
||||
vertices.push(Vertex {
|
||||
position: [px, py, pz],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [fx, fy],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for y in 0..subdivisions_y
|
||||
{
|
||||
for x in 0..subdivisions_x
|
||||
{
|
||||
let row_stride = subdivisions_x + 1;
|
||||
let i0 = y * row_stride + x;
|
||||
let i1 = i0 + 1;
|
||||
let i2 = i0 + row_stride;
|
||||
let i3 = i2 + 1;
|
||||
|
||||
indices.push(i0);
|
||||
indices.push(i2);
|
||||
indices.push(i1);
|
||||
|
||||
indices.push(i1);
|
||||
indices.push(i2);
|
||||
indices.push(i3);
|
||||
}
|
||||
}
|
||||
|
||||
Mesh::new(device, &vertices, &indices)
|
||||
}
|
||||
|
||||
pub fn create_wireframe_box(device: &wgpu::Device) -> Mesh
|
||||
{
|
||||
let vertices = vec![
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, -0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, -0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5, 0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, 0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, -0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, -0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5, 0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5, 0.5],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
];
|
||||
|
||||
let indices = vec![
|
||||
0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7,
|
||||
];
|
||||
|
||||
Mesh::new(device, &vertices, &indices)
|
||||
}
|
||||
|
||||
pub fn load_gltf_mesh(
|
||||
device: &wgpu::Device,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<Mesh, Box<dyn std::error::Error>>
|
||||
{
|
||||
let (gltf, buffers, _images) = gltf::import(path)?;
|
||||
|
||||
let mut all_vertices = Vec::new();
|
||||
let mut all_indices = Vec::new();
|
||||
|
||||
for scene in gltf.scenes()
|
||||
{
|
||||
for node in scene.nodes()
|
||||
{
|
||||
Self::process_node(
|
||||
&node,
|
||||
&buffers,
|
||||
Mat4::IDENTITY,
|
||||
&mut all_vertices,
|
||||
&mut all_indices,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Mesh::new(device, &all_vertices, &all_indices))
|
||||
}
|
||||
|
||||
fn process_node(
|
||||
node: &gltf::Node,
|
||||
buffers: &[gltf::buffer::Data],
|
||||
parent_transform: Mat4,
|
||||
all_vertices: &mut Vec<Vertex>,
|
||||
all_indices: &mut Vec<u32>,
|
||||
) -> Result<(), Box<dyn std::error::Error>>
|
||||
{
|
||||
let local_transform = Mat4::from_cols_array_2d(&node.transform().matrix());
|
||||
let global_transform = parent_transform * local_transform;
|
||||
|
||||
if let Some(mesh) = node.mesh()
|
||||
{
|
||||
for primitive in mesh.primitives()
|
||||
{
|
||||
let reader =
|
||||
primitive.reader(|buffer| buffers.get(buffer.index()).map(|data| &data[..]));
|
||||
|
||||
let positions = reader
|
||||
.read_positions()
|
||||
.ok_or("Missing position data")?
|
||||
.collect::<Vec<[f32; 3]>>();
|
||||
|
||||
let normals = reader
|
||||
.read_normals()
|
||||
.ok_or("Missing normal data")?
|
||||
.collect::<Vec<[f32; 3]>>();
|
||||
|
||||
let uvs = reader
|
||||
.read_tex_coords(0)
|
||||
.map(|iter| iter.into_f32().collect::<Vec<[f32; 2]>>())
|
||||
.unwrap_or_else(|| vec![[0.0, 0.0]; positions.len()]);
|
||||
|
||||
let base_index = all_vertices.len() as u32;
|
||||
|
||||
let normal_matrix = global_transform.inverse().transpose();
|
||||
|
||||
for ((pos, normal), uv) in positions.iter().zip(normals.iter()).zip(uvs.iter())
|
||||
{
|
||||
let pos_vec3 = Vec3::from(*pos);
|
||||
let normal_vec3 = Vec3::from(*normal);
|
||||
|
||||
let transformed_pos = global_transform.transform_point3(pos_vec3);
|
||||
let transformed_normal =
|
||||
normal_matrix.transform_vector3(normal_vec3).normalize();
|
||||
|
||||
all_vertices.push(Vertex {
|
||||
position: transformed_pos.into(),
|
||||
normal: transformed_normal.into(),
|
||||
uv: *uv,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(indices_reader) = reader.read_indices()
|
||||
{
|
||||
all_indices.extend(indices_reader.into_u32().map(|i| i + base_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for child in node.children()
|
||||
{
|
||||
Self::process_node(&child, buffers, global_transform, all_vertices, all_indices)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_mesh(path: impl AsRef<Path>) -> Result<Mesh, Box<dyn std::error::Error>>
|
||||
{
|
||||
crate::render::with_device(|device| Mesh::load_gltf_mesh(device, path))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user