Add support for binary glTF (.glb) (#271)

Add support for binary glTF (.glb)
This commit is contained in:
Elias 2020-08-26 01:55:08 +02:00 committed by GitHub
parent c9000deafa
commit 9aff0bcc2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 9 deletions

Binary file not shown.

View file

@ -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<Mesh> 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<PrimitiveTopology, GltfError> {
// TODO: this should return a scene
pub fn load_gltf(asset_path: &Path, bytes: Vec<u8>) -> Result<Mesh, GltfError> {
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<u8>], node: &gltf::Node, depth: i32) -> Result<M
panic!("failed to find mesh")
}
fn load_buffers(buffers: iter::Buffers, asset_path: &Path) -> Result<Vec<Vec<u8>>, GltfError> {
fn load_buffers(gltf: &gltf::Gltf, asset_path: &Path) -> Result<Vec<Vec<u8>>, 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<Vec<Vec<u8>
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);
}
}
}
}

View file

@ -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