Load basic glTF geometry
This commit is contained in:
parent
bb1f7580f7
commit
41e5c23c75
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
152
src/model.rs
152
src/model.rs
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue