Load basic glTF geometry
This commit is contained in:
parent
bb1f7580f7
commit
41e5c23c75
|
@ -6,7 +6,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = { version="1.7", features=["derive"] }
|
bytemuck = { version="1.7", features=["derive"] }
|
||||||
glam = "0.20"
|
glam = "0.20"
|
||||||
gltf = "1.0"
|
gltf = { version="1.0", features=["utils"] }
|
||||||
image = "0.24"
|
image = "0.24"
|
||||||
pollster = "0.2"
|
pollster = "0.2"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct Grid {
|
||||||
|
|
||||||
impl Grid {
|
impl Grid {
|
||||||
fn new(ren: &mut Renderer) -> Self {
|
fn new(ren: &mut Renderer) -> Self {
|
||||||
let model = ObjModel::load(ren);
|
let model = GltfModel::load(ren);
|
||||||
let mut meshes = Vec::new();
|
let mut meshes = Vec::new();
|
||||||
for x in -5..5 {
|
for x in -5..5 {
|
||||||
for y in -5..5 {
|
for y in -5..5 {
|
||||||
|
@ -61,13 +61,13 @@ struct Planet {
|
||||||
struct Planets {
|
struct Planets {
|
||||||
start: std::time::Instant,
|
start: std::time::Instant,
|
||||||
planets: Vec<Planet>,
|
planets: Vec<Planet>,
|
||||||
model: ObjModel,
|
model: GltfModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Planets {
|
impl Planets {
|
||||||
fn new(ren: &mut Renderer) -> Self {
|
fn new(ren: &mut Renderer) -> Self {
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let model = ObjModel::load(ren);
|
let model = GltfModel::load(ren);
|
||||||
|
|
||||||
let mut planets = Vec::new();
|
let mut planets = Vec::new();
|
||||||
for i in 0..10 {
|
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::renderer::Renderer;
|
||||||
use crate::scene::MeshInstance;
|
use crate::scene::MeshInstance;
|
||||||
|
|
||||||
pub struct ObjModel {
|
pub struct BasicMesh {
|
||||||
pub mesh_handle: MeshHandle,
|
pub mesh_handle: MeshHandle,
|
||||||
pub material_handle: MaterialHandle,
|
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 {
|
impl ObjModel {
|
||||||
pub fn load(ren: &mut Renderer) -> Self {
|
pub fn load(ren: &mut Renderer) -> Self {
|
||||||
use tobj::*;
|
use tobj::*;
|
||||||
|
@ -80,43 +94,59 @@ impl ObjModel {
|
||||||
ren.material_pool
|
ren.material_pool
|
||||||
.allocate(&ren.device, &ren.texture_pool, &material_data);
|
.allocate(&ren.device, &ren.texture_pool, &material_data);
|
||||||
|
|
||||||
Self {
|
let mesh = BasicMesh {
|
||||||
mesh_handle,
|
mesh_handle,
|
||||||
material_handle,
|
material_handle,
|
||||||
}
|
};
|
||||||
|
Self { mesh }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, meshes: &mut Vec<MeshInstance>, transform: glam::Mat4) {
|
pub fn draw(&self, meshes: &mut Vec<MeshInstance>, transform: glam::Mat4) {
|
||||||
meshes.push(MeshInstance {
|
meshes.push(self.mesh.instantiate(transform));
|
||||||
mesh: self.mesh_handle,
|
|
||||||
material: self.material_handle,
|
|
||||||
transform,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GltfModel {}
|
pub struct GltfModel {
|
||||||
|
meshes: Vec<BasicMesh>,
|
||||||
|
}
|
||||||
|
|
||||||
impl GltfModel {
|
impl GltfModel {
|
||||||
pub fn new(ren: &mut Renderer) -> Self {
|
pub fn load(ren: &mut Renderer) -> Self {
|
||||||
use gltf::*;
|
use gltf::*;
|
||||||
|
|
||||||
let model_data = include_bytes!("assets/DamagedHelmet.glb");
|
let model_data = include_bytes!("assets/DamagedHelmet.glb");
|
||||||
let model = Gltf::from_slice(model_data.as_slice()).unwrap();
|
let model = Gltf::from_slice(model_data.as_slice()).unwrap();
|
||||||
let loader = GltfLoader::load(&model, ren);
|
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 struct GltfLoader<'a> {
|
||||||
pub model: &'a gltf::Gltf,
|
pub model: &'a gltf::Gltf,
|
||||||
|
pub buffers: Vec<Vec<u8>>,
|
||||||
pub ren: &'a mut Renderer,
|
pub ren: &'a mut Renderer,
|
||||||
|
pub meshes: Vec<BasicMesh>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GltfLoader<'a> {
|
impl<'a> GltfLoader<'a> {
|
||||||
pub fn load(model: &'a gltf::Gltf, ren: &'a mut Renderer) -> Self {
|
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 scene in loader.model.scenes() {
|
||||||
for node in scene.nodes() {
|
for node in scene.nodes() {
|
||||||
|
@ -127,10 +157,25 @@ impl<'a> GltfLoader<'a> {
|
||||||
loader
|
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) {
|
pub fn load_node(&mut self, node: gltf::Node) {
|
||||||
if let Some(mesh) = node.mesh() {
|
if let Some(mesh) = node.mesh() {
|
||||||
for primitive in mesh.primitives() {
|
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 {
|
if primitive.mode() != gltf::mesh::Mode::Triangles {
|
||||||
panic!("glTF primitive must be triangle list");
|
panic!("glTF primitive must be triangle list");
|
||||||
}
|
}
|
||||||
|
|
||||||
let attributes = GltfPrimitiveAttributes::new(primitive);
|
println!("primitive: {:#?}", primitive);
|
||||||
let positions = attributes.positions.unwrap();
|
|
||||||
let normals = attributes.normals.unwrap();
|
let reader = primitive.reader(|buffer| Some(&self.buffers[buffer.index()]));
|
||||||
let texcoords = attributes.texcoords.unwrap();
|
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