diff --git a/assets/models/monkey/Monkey.glb b/assets/models/monkey/Monkey.glb new file mode 100644 index 0000000000000..1998f1dbe1cf3 Binary files /dev/null and b/assets/models/monkey/Monkey.glb differ diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index ad8441657e5a3..4016d7d6631f4 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -5,7 +5,7 @@ use bevy_render::{ use anyhow::Result; use bevy_asset::AssetLoader; -use gltf::{buffer::Source, iter, mesh::Mode}; +use gltf::{buffer::Source, mesh::Mode}; use std::{fs, io, path::Path}; use thiserror::Error; @@ -22,7 +22,7 @@ impl AssetLoader for GltfLoader { } fn extensions(&self) -> &[&str] { - static EXTENSIONS: &[&str] = &["gltf"]; + static EXTENSIONS: &[&str] = &["gltf", "glb"]; EXTENSIONS } } @@ -36,8 +36,8 @@ pub enum GltfError { Gltf(#[from] gltf::Error), #[error("Failed to load file.")] Io(#[from] io::Error), - #[error("Binary buffers not supported yet.")] - BinaryBuffersUnsupported, + #[error("Binary blob is missing.")] + MissingBlob, #[error("Failed to decode base64 mesh data.")] Base64Decode(#[from] base64::DecodeError), #[error("Unsupported buffer format.")] @@ -58,7 +58,7 @@ fn get_primitive_topology(mode: Mode) -> Result { // TODO: this should return a scene pub fn load_gltf(asset_path: &Path, bytes: Vec) -> Result { let gltf = gltf::Gltf::from_slice(&bytes)?; - let buffer_data = load_buffers(gltf.buffers(), asset_path)?; + let buffer_data = load_buffers(&gltf, asset_path)?; for scene in gltf.scenes() { if let Some(node) = scene.nodes().next() { return Ok(load_node(&buffer_data, &node, 1)?); @@ -112,11 +112,11 @@ fn load_node(buffer_data: &[Vec], node: &gltf::Node, depth: i32) -> Result Result>, GltfError> { +fn load_buffers(gltf: &gltf::Gltf, asset_path: &Path) -> Result>, GltfError> { const OCTET_STREAM_URI: &str = "data:application/octet-stream;base64,"; let mut buffer_data = Vec::new(); - for buffer in buffers { + for buffer in gltf.buffers() { match buffer.source() { Source::Uri(uri) => { if uri.starts_with("data:") { @@ -131,7 +131,13 @@ fn load_buffers(buffers: iter::Buffers, asset_path: &Path) -> Result buffer_data.push(buffer_bytes); } } - Source::Bin => return Err(GltfError::BinaryBuffersUnsupported), + Source::Bin => { + if let Some(blob) = gltf.blob.as_deref() { + buffer_data.push(blob.into()); + } else { + return Err(GltfError::MissingBlob); + } + } } } diff --git a/examples/3d/load_model.rs b/examples/3d/load_model.rs index 6781b44a402d4..f83f94a8751ff 100644 --- a/examples/3d/load_model.rs +++ b/examples/3d/load_model.rs @@ -17,12 +17,24 @@ fn setup( commands // mesh .spawn(PbrComponents { - // load the mesh + // load a mesh from glTF mesh: asset_server .load("assets/models/monkey/Monkey.gltf") .unwrap(), // create a material for the mesh material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()), + translation: Translation::new(-1.5, 0.0, 0.0), + ..Default::default() + }) + // mesh + .spawn(PbrComponents { + // load a mesh from binary glTF + mesh: asset_server + .load("assets/models/monkey/Monkey.glb") + .unwrap(), + // create a material for the mesh + material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()), + translation: Translation::new(1.5, 0.0, 0.0), ..Default::default() }) // light