Load basic glTF geometry

This commit is contained in:
marceline-cramer 2022-02-14 19:22:22 -07:00
parent bb1f7580f7
commit 41e5c23c75
3 changed files with 138 additions and 22 deletions

View File

@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
bytemuck = { version="1.7", features=["derive"] }
glam = "0.20"
gltf = "1.0"
gltf = { version="1.0", features=["utils"] }
image = "0.24"
pollster = "0.2"
slab = "0.4"

View File

@ -29,7 +29,7 @@ struct Grid {
impl Grid {
fn new(ren: &mut Renderer) -> Self {
let model = ObjModel::load(ren);
let model = GltfModel::load(ren);
let mut meshes = Vec::new();
for x in -5..5 {
for y in -5..5 {
@ -61,13 +61,13 @@ struct Planet {
struct Planets {
start: std::time::Instant,
planets: Vec<Planet>,
model: ObjModel,
model: GltfModel,
}
impl Planets {
fn new(ren: &mut Renderer) -> Self {
let start = std::time::Instant::now();
let model = ObjModel::load(ren);
let model = GltfModel::load(ren);
let mut planets = Vec::new();
for i in 0..10 {

View File

@ -4,11 +4,25 @@ use crate::pool::{MaterialData, TextureData};
use crate::renderer::Renderer;
use crate::scene::MeshInstance;
pub struct ObjModel {
pub struct BasicMesh {
pub mesh_handle: MeshHandle,
pub material_handle: MaterialHandle,
}
impl BasicMesh {
pub fn instantiate(&self, transform: glam::Mat4) -> MeshInstance {
MeshInstance {
mesh: self.mesh_handle,
material: self.material_handle,
transform,
}
}
}
pub struct ObjModel {
mesh: BasicMesh,
}
impl ObjModel {
pub fn load(ren: &mut Renderer) -> Self {
use tobj::*;
@ -80,43 +94,59 @@ impl ObjModel {
ren.material_pool
.allocate(&ren.device, &ren.texture_pool, &material_data);
Self {
let mesh = BasicMesh {
mesh_handle,
material_handle,
}
};
Self { mesh }
}
pub fn draw(&self, meshes: &mut Vec<MeshInstance>, transform: glam::Mat4) {
meshes.push(MeshInstance {
mesh: self.mesh_handle,
material: self.material_handle,
transform,
});
meshes.push(self.mesh.instantiate(transform));
}
}
pub struct GltfModel {}
pub struct GltfModel {
meshes: Vec<BasicMesh>,
}
impl GltfModel {
pub fn new(ren: &mut Renderer) -> Self {
pub fn load(ren: &mut Renderer) -> Self {
use gltf::*;
let model_data = include_bytes!("assets/DamagedHelmet.glb");
let model = Gltf::from_slice(model_data.as_slice()).unwrap();
let loader = GltfLoader::load(&model, ren);
Self {}
Self {
meshes: loader.meshes,
}
}
pub fn draw(&self, meshes: &mut Vec<MeshInstance>, transform: glam::Mat4) {
for mesh in self.meshes.iter() {
meshes.push(mesh.instantiate(transform));
}
}
}
pub struct GltfLoader<'a> {
pub model: &'a gltf::Gltf,
pub buffers: Vec<Vec<u8>>,
pub ren: &'a mut Renderer,
pub meshes: Vec<BasicMesh>,
}
impl<'a> GltfLoader<'a> {
pub fn load(model: &'a gltf::Gltf, ren: &'a mut Renderer) -> Self {
let mut loader = Self { model, ren };
let buffers = Self::load_buffers(model);
let mut loader = Self {
model,
buffers,
ren,
meshes: Default::default(),
};
for scene in loader.model.scenes() {
for node in scene.nodes() {
@ -127,10 +157,25 @@ impl<'a> GltfLoader<'a> {
loader
}
pub fn load_buffers(model: &gltf::Gltf) -> Vec<Vec<u8>> {
let mut buffer_data = Vec::<Vec<u8>>::new();
for buffer in model.buffers() {
match buffer.source() {
gltf::buffer::Source::Bin => {
buffer_data.push(model.blob.as_deref().unwrap().into());
}
_ => panic!("URI buffer sources are unsupported"),
}
}
buffer_data
}
pub fn load_node(&mut self, node: gltf::Node) {
if let Some(mesh) = node.mesh() {
for primitive in mesh.primitives() {
self.load_primitive(primitive);
let mesh = self.load_primitive(primitive);
self.meshes.push(mesh);
}
}
@ -139,15 +184,86 @@ impl<'a> GltfLoader<'a> {
}
}
pub fn load_primitive(&mut self, primitive: gltf::Primitive) {
pub fn load_primitive(&mut self, primitive: gltf::Primitive) -> BasicMesh {
let material_handle = self.load_primitive_material(primitive.clone());
let mesh_handle = self.load_primitive_mesh(primitive);
BasicMesh {
material_handle,
mesh_handle,
}
}
pub fn load_primitive_material(&mut self, primitive: gltf::Primitive) -> MaterialHandle {
let pbr = primitive.material().pbr_metallic_roughness();
let base_texture = pbr.base_color_texture().unwrap();
let base_texture = base_texture.texture().source().source();
let base_view = if let gltf::image::Source::View { view, .. } = base_texture {
view
} else {
panic!("texture must be embedded");
};
// TODO put real data in albedo texture
let albedo_data = TextureData {
width: 256,
height: 256,
data: vec![0xffu8; 256 * 256 * 4],
};
let albedo =
self.ren
.texture_pool
.allocate(&self.ren.device, &self.ren.queue, &albedo_data);
let material_data = MaterialData { albedo };
self.ren
.material_pool
.allocate(&self.ren.device, &self.ren.texture_pool, &material_data)
}
pub fn load_primitive_mesh(&mut self, primitive: gltf::Primitive) -> MeshHandle {
use gltf::mesh::util::{ReadIndices, ReadTexCoords};
if primitive.mode() != gltf::mesh::Mode::Triangles {
panic!("glTF primitive must be triangle list");
}
let attributes = GltfPrimitiveAttributes::new(primitive);
let positions = attributes.positions.unwrap();
let normals = attributes.normals.unwrap();
let texcoords = attributes.texcoords.unwrap();
println!("primitive: {:#?}", primitive);
let reader = primitive.reader(|buffer| Some(&self.buffers[buffer.index()]));
let positions = reader.read_positions().unwrap();
let mut normals = reader.read_normals().unwrap();
let tex_coords = reader.read_tex_coords(0).unwrap();
let mut tex_coords = if let ReadTexCoords::F32(tex_coords) = tex_coords {
tex_coords
} else {
panic!("only f32 texture coordinates are supported")
};
let mut vertices = Vec::new();
for position in positions {
let normal = normals.next().unwrap();
let tex_coords = tex_coords.next().unwrap();
vertices.push(Vertex {
position,
normal,
tex_coords,
});
}
let indices = match reader.read_indices().unwrap() {
ReadIndices::U32(indices) => indices.collect(),
ReadIndices::U16(indices) => indices.map(|i| i as u32).collect(),
ReadIndices::U8(indices) => indices.map(|i| i as u32).collect(),
};
let mesh_data = MeshData { vertices, indices };
self.ren.mesh_pool.allocate(&self.ren.device, &mesh_data)
}
}