Add MeshVertexAttribute instead of directly storing positions
This commit is contained in:
parent
e76ca1ec50
commit
64817b6142
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
|
|
||||||
use crate::{ResourceLoader, LoaderError, Mesh, Vertex, Model};
|
use crate::{ResourceLoader, LoaderError, Mesh, Vertex, Model, MeshVertexAttribute, VertexAttributeData};
|
||||||
|
|
||||||
impl From<gltf::Error> for LoaderError {
|
impl From<gltf::Error> for LoaderError {
|
||||||
fn from(value: gltf::Error) -> Self {
|
fn from(value: gltf::Error) -> Self {
|
||||||
|
@ -35,25 +35,44 @@ impl ModelLoader {
|
||||||
let mut meshes = vec![];
|
let mut meshes = vec![];
|
||||||
if let Some(mesh) = node.mesh() {
|
if let Some(mesh) = node.mesh() {
|
||||||
for prim in mesh.primitives() {
|
for prim in mesh.primitives() {
|
||||||
let pos_accessor = prim.get(&gltf::Semantic::Positions).unwrap();
|
|
||||||
//assert_eq!(pos_accessor.dimensions(), gltf::accessor::Dimensions::Vec3); // TODO: dont do this
|
|
||||||
|
|
||||||
let reader = prim.reader(|buf| Some(buffers[buf.index()].as_slice()));
|
let reader = prim.reader(|buf| Some(buffers[buf.index()].as_slice()));
|
||||||
let pos: Vec<Vec3> = reader.read_positions()
|
|
||||||
.unwrap()
|
|
||||||
.map(|pos| Vec3::new(pos[0], pos[1], pos[2]))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let indices: Option<Vec<u32>> = reader.read_indices()
|
let mut new_mesh = Mesh::default();
|
||||||
.map(|i| match i {
|
|
||||||
|
// read the positions
|
||||||
|
if let Some(pos) = reader.read_positions() {
|
||||||
|
let pos: Vec<glam::Vec3> = pos.map(|t| t.into()).collect();
|
||||||
|
new_mesh.add_attribute(MeshVertexAttribute::Position, VertexAttributeData::Vec3(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the normals
|
||||||
|
if let Some(norms) = reader.read_normals() {
|
||||||
|
let norms: Vec<glam::Vec3> = norms.map(|t| t.into()).collect();
|
||||||
|
new_mesh.add_attribute(MeshVertexAttribute::Normals, VertexAttributeData::Vec3(norms));
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the tangents
|
||||||
|
if let Some(tangents) = reader.read_tangents() {
|
||||||
|
let tangents: Vec<glam::Vec4> = tangents.map(|t| t.into()).collect();
|
||||||
|
new_mesh.add_attribute(MeshVertexAttribute::Tangents, VertexAttributeData::Vec4(tangents));
|
||||||
|
}
|
||||||
|
|
||||||
|
// read tex coords
|
||||||
|
if let Some(tex_coords) = reader.read_tex_coords(0) {
|
||||||
|
let tex_coords: Vec<glam::Vec2> = tex_coords.into_f32().map(|t| t.into()).collect(); // TODO: u16, u8
|
||||||
|
new_mesh.add_attribute(MeshVertexAttribute::TexCoords, VertexAttributeData::Vec2(tex_coords));
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the indices
|
||||||
|
if let Some(indices) = reader.read_indices() {
|
||||||
|
let indices: Vec<u32> = match indices {
|
||||||
gltf::mesh::util::ReadIndices::U8(i) => i.map(|i| i as u32).collect(),
|
gltf::mesh::util::ReadIndices::U8(i) => i.map(|i| i as u32).collect(),
|
||||||
gltf::mesh::util::ReadIndices::U16(i) => i.map(|i| i as u32).collect(),
|
gltf::mesh::util::ReadIndices::U16(i) => i.map(|i| i as u32).collect(),
|
||||||
gltf::mesh::util::ReadIndices::U32(i) => i.collect(),
|
gltf::mesh::util::ReadIndices::U32(i) => i.collect(),
|
||||||
});
|
};
|
||||||
|
|
||||||
let mut new_mesh = Mesh::default();
|
new_mesh.indices = Some(indices);
|
||||||
new_mesh.vertices = pos.into_iter().map(|p| Vertex::new(p, glam::Vec2::new(0.0, 0.0))).collect();
|
}
|
||||||
new_mesh.indices = indices;
|
|
||||||
|
|
||||||
meshes.push(new_mesh);
|
meshes.push(new_mesh);
|
||||||
}
|
}
|
||||||
|
@ -82,8 +101,6 @@ impl ResourceLoader for ModelLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
let gltf = gltf::Gltf::open(path)?;
|
let gltf = gltf::Gltf::open(path)?;
|
||||||
|
|
||||||
//let buffers: Vec<gltf::Buffer<'_>> = gltf.buffers().collect();
|
|
||||||
|
|
||||||
let buffers: Vec<Vec<u8>> = gltf.buffers().map(|b| match b.source() {
|
let buffers: Vec<Vec<u8>> = gltf.buffers().map(|b| match b.source() {
|
||||||
gltf::buffer::Source::Bin => gltf.blob.as_deref().map(|v| v.to_vec()),
|
gltf::buffer::Source::Bin => gltf.blob.as_deref().map(|v| v.to_vec()),
|
||||||
|
@ -93,6 +110,8 @@ impl ResourceLoader for ModelLoader {
|
||||||
// TODO: Read in multiple scenes
|
// TODO: Read in multiple scenes
|
||||||
let scene = gltf.scenes().next().unwrap();
|
let scene = gltf.scenes().next().unwrap();
|
||||||
|
|
||||||
|
// TODO: materials
|
||||||
|
|
||||||
let meshes: Vec<Mesh> = scene.nodes()
|
let meshes: Vec<Mesh> = scene.nodes()
|
||||||
.map(|node| self.process_node(&buffers, node))
|
.map(|node| self.process_node(&buffers, node))
|
||||||
.flatten().collect();
|
.flatten().collect();
|
||||||
|
@ -119,8 +138,11 @@ mod tests {
|
||||||
let loader = ModelLoader::default();
|
let loader = ModelLoader::default();
|
||||||
let model = loader.load(&path).unwrap();
|
let model = loader.load(&path).unwrap();
|
||||||
let model = Arc::downcast::<Model>(model.as_arc_any()).unwrap();
|
let model = Arc::downcast::<Model>(model.as_arc_any()).unwrap();
|
||||||
|
assert_eq!(model.meshes.len(), 1); // There should only be 1 mesh
|
||||||
let mesh = &model.meshes[0];
|
let mesh = &model.meshes[0];
|
||||||
assert!(mesh.vertices.len() > 0);
|
assert!(mesh.position().unwrap().len() > 0);
|
||||||
|
assert!(mesh.normals().unwrap().len() > 0);
|
||||||
|
assert!(mesh.tex_coords().unwrap().len() > 0);
|
||||||
assert!(mesh.indices.clone().unwrap().len() > 0);
|
assert!(mesh.indices.clone().unwrap().len() > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -15,12 +17,79 @@ impl Vertex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum VertexAttributeData {
|
||||||
|
Vec2(Vec<glam::Vec2>),
|
||||||
|
Vec3(Vec<glam::Vec3>),
|
||||||
|
Vec4(Vec<glam::Vec4>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VertexAttributeData {
|
||||||
|
/// Take self as a list of Vec2's
|
||||||
|
pub fn as_vec2(&self) -> &Vec<glam::Vec2> {
|
||||||
|
match self {
|
||||||
|
VertexAttributeData::Vec2(v) => v,
|
||||||
|
_ => panic!("Attempt to get {self:?} as `Vec2`"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_vec3(&self) -> &Vec<glam::Vec3> {
|
||||||
|
match self {
|
||||||
|
VertexAttributeData::Vec3(v) => v,
|
||||||
|
_ => panic!("Attempt to get {self:?} as `Vec3`"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum MeshVertexAttribute {
|
||||||
|
Position,
|
||||||
|
Normals,
|
||||||
|
Tangents,
|
||||||
|
// Colors, // TODO: Store data in VertexAttributeData
|
||||||
|
Joints, // TODO: Animation
|
||||||
|
TexCoords,
|
||||||
|
Weights, // TODO: Animation
|
||||||
|
MorphTargets, // TODO: Animation
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Mesh {
|
pub struct Mesh {
|
||||||
pub vertices: Vec<Vertex>,
|
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
|
||||||
pub indices: Option<Vec<u32>>,
|
pub indices: Option<Vec<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Mesh {
|
||||||
|
pub fn add_attribute(&mut self, attribute: MeshVertexAttribute, data: VertexAttributeData) {
|
||||||
|
self.attributes.insert(attribute, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to get the position attribute of the Mesh
|
||||||
|
pub fn position(&self) -> Option<&Vec<glam::Vec3>> {
|
||||||
|
self.attributes.get(&MeshVertexAttribute::Position)
|
||||||
|
.map(|p| p.as_vec3())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_position(&mut self, pos: Vec<glam::Vec3>) {
|
||||||
|
self.attributes.insert(MeshVertexAttribute::Position, VertexAttributeData::Vec3(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to get the normals attribute of the Mesh
|
||||||
|
pub fn normals(&self) -> Option<&Vec<glam::Vec3>> {
|
||||||
|
self.attributes.get(&MeshVertexAttribute::Normals)
|
||||||
|
.map(|p| p.as_vec3())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to get the texture coordinates attribute of the Mesh
|
||||||
|
pub fn tex_coords(&self) -> Option<&Vec<glam::Vec2>> {
|
||||||
|
self.attributes.get(&MeshVertexAttribute::TexCoords)
|
||||||
|
.map(|p| p.as_vec2())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
pub meshes: Vec<Mesh>,
|
pub meshes: Vec<Mesh>,
|
||||||
//pub material
|
//pub material
|
||||||
|
|
Loading…
Reference in New Issue