Skip to content

Commit

Permalink
added support for KHR_mesh_quantization
Browse files Browse the repository at this point in the history
  • Loading branch information
sotrh committed Jul 23, 2024
1 parent a29fb75 commit 6dc0f3a
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 25 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ KHR_materials_variants = ["gltf-json/KHR_materials_variants"]
KHR_materials_volume = ["gltf-json/KHR_materials_volume"]
KHR_materials_specular = ["gltf-json/KHR_materials_specular"]
KHR_materials_emissive_strength = ["gltf-json/KHR_materials_emissive_strength"]
KHR_mesh_quantization = ["gltf-json/KHR_mesh_quantization"]
EXT_texture_webp = ["gltf-json/EXT_texture_webp", "image/webp"]
guess_mime_type = []

Expand Down
1 change: 1 addition & 0 deletions gltf-json/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ KHR_materials_variants = []
KHR_materials_volume = []
KHR_texture_transform = []
KHR_materials_emissive_strength = []
KHR_mesh_quantization = []
EXT_texture_webp = []
3 changes: 3 additions & 0 deletions gltf-json/src/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub const ENABLED_EXTENSIONS: &[&str] = &[
"KHR_materials_ior",
#[cfg(feature = "KHR_materials_emissive_strength")]
"KHR_materials_emissive_strength",
#[cfg(feature = "KHR_mesh_quantization")]
"KHR_mesh_quantization",
// Allowlisted texture extensions. Processing is delegated to the user.
#[cfg(feature = "allow_empty_texture")]
"KHR_texture_basisu",
Expand All @@ -70,5 +72,6 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
"KHR_materials_transmission",
"KHR_materials_ior",
"KHR_materials_emissive_strength",
"KHR_mesh_quantization",
"EXT_texture_webp",
];
34 changes: 21 additions & 13 deletions gltf-json/src/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ mod tests {
};

let mut errors = Vec::new();
root.validate(&root, Path::new, &mut |path, error| {
root.validate(&root, Path::new, &mut |path: &dyn Fn() -> Path, error| {
errors.push((path(), error));
});

Expand All @@ -486,17 +486,25 @@ mod tests {
assert_eq!(*error, Error::Unsupported);
}

root.extensions_required = vec!["KHR_mesh_quantization".to_owned()];
errors.clear();
root.validate(&root, Path::new, &mut |path, error| {
errors.push((path(), error));
});
assert_eq!(1, errors.len());
let (path, error) = errors.get(0).unwrap();
assert_eq!(
path.as_str(),
"extensionsRequired[0] = \"KHR_mesh_quantization\""
);
assert_eq!(*error, Error::Unsupported);
#[cfg(feature = "KHR_mesh_quantization")]
{
assert!(errors.is_empty());
}

#[cfg(not(feature = "KHR_mesh_quantization"))]
{
root.extensions_required = vec!["KHR_mesh_quantization".to_owned()];
errors.clear();
root.validate(&root, Path::new, &mut |path, error| {
errors.push((path(), error));
});
assert_eq!(1, errors.len());
let (path, error) = errors.get(0).unwrap();
assert_eq!(
path.as_str(),
"extensionsRequired[0] = \"KHR_mesh_quantization\""
);
assert_eq!(*error, Error::Unsupported);
}
}
}
88 changes: 79 additions & 9 deletions src/mesh/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,17 @@
//! for primitive in mesh.primitives() {
//! println!("- Primitive #{}", primitive.index());
//! let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
//! if let Some(iter) = reader.read_positions() {
//! for vertex_position in iter {
//! println!("{:?}", vertex_position);
//! }
//!
//! #[cfg(not(feature="KHR_mesh_quantization"))]
//! let positions = reader.read_positions();
//! #[cfg(feature="KHR_mesh_quantization")]
//! let positions = match reader.read_positions() {
//! Some(gltf::mesh::util::ReadPositions::F32(iter)) => iter,
//! _ => unreachable!(),
//! };
//!
//! for vertex_position in positions {
//! println!("{:?}", vertex_position);
//! }
//! }
//! }
Expand Down Expand Up @@ -336,21 +343,84 @@ where
pub fn read_positions(&self) -> Option<util::ReadPositions<'s>> {
self.primitive
.get(&Semantic::Positions)
.and_then(|accessor| accessor::Iter::new(accessor, self.get_buffer_data.clone()))
.and_then(|accessor| {
#[cfg(feature = "KHR_mesh_quantization")]
match accessor.data_type() {
json::accessor::ComponentType::I8 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadPositions::I8(iter))
}
json::accessor::ComponentType::U8 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadPositions::U8(iter))
}
json::accessor::ComponentType::I16 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadPositions::I16(iter))
}
json::accessor::ComponentType::U16 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadPositions::U16(iter))
}
json::accessor::ComponentType::F32 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadPositions::F32(iter))
}
_ => None,
}
#[cfg(not(feature = "KHR_mesh_quantization"))]
accessor::Iter::new(accessor, self.get_buffer_data.clone())
})
}

/// Visits the vertex normals of a primitive.
pub fn read_normals(&self) -> Option<util::ReadNormals<'s>> {
self.primitive
.get(&Semantic::Normals)
.and_then(|accessor| accessor::Iter::new(accessor, self.get_buffer_data.clone()))
self.primitive.get(&Semantic::Normals).and_then(|accessor| {
#[cfg(feature = "KHR_mesh_quantization")]
match accessor.data_type() {
json::accessor::ComponentType::I8 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadNormals::I8(iter))
}
json::accessor::ComponentType::I16 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadNormals::I16(iter))
}
json::accessor::ComponentType::F32 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadNormals::F32(iter))
}
_ => None,
}
#[cfg(not(feature = "KHR_mesh_quantization"))]
accessor::Iter::new(accessor, self.get_buffer_data.clone())
})
}

/// Visits the vertex tangents of a primitive.
pub fn read_tangents(&self) -> Option<util::ReadTangents<'s>> {
self.primitive
.get(&Semantic::Tangents)
.and_then(|accessor| accessor::Iter::new(accessor, self.get_buffer_data.clone()))
.and_then(|accessor| {
#[cfg(feature = "KHR_mesh_quantization")]
match accessor.data_type() {
json::accessor::ComponentType::I8 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadTangents::I8(iter))
}
json::accessor::ComponentType::I16 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadTangents::I16(iter))
}
json::accessor::ComponentType::F32 => {
accessor::Iter::new(accessor, self.get_buffer_data.clone())
.map(|iter| util::ReadTangents::F32(iter))
}
_ => None,
}
#[cfg(not(feature = "KHR_mesh_quantization"))]
accessor::Iter::new(accessor, self.get_buffer_data.clone())
})
}

/// Visits the vertex colors of a primitive.
Expand Down
55 changes: 55 additions & 0 deletions src/mesh/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,70 @@ use crate::accessor::Iter;
use crate::Buffer;

/// XYZ vertex positions of type `[f32; 3]`.
#[cfg(not(feature = "KHR_mesh_quantization"))]
pub type ReadPositions<'a> = Iter<'a, [f32; 3]>;

/// XYZ vertex positions as potentially quantized data
#[cfg(feature = "KHR_mesh_quantization")]
pub enum ReadPositions<'a> {
/// Position data of type I8
I8(Iter<'a, [i8; 3]>),
/// Position data of type U8
U8(Iter<'a, [u8; 3]>),
/// Position data of type I16
I16(Iter<'a, [i16; 3]>),
/// Position data of type U16
U16(Iter<'a, [u16; 3]>),
/// Position data of type F32
F32(Iter<'a, [f32; 3]>),
}

#[cfg(feature = "KHR_mesh_quantization")]
impl<'a> ReadPositions<'a> {
/// Returns size hint of internal iterator
pub fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::I8(iter) => iter.size_hint(),
Self::U8(iter) => iter.size_hint(),
Self::I16(iter) => iter.size_hint(),
Self::U16(iter) => iter.size_hint(),
Self::F32(iter) => iter.size_hint(),
}
}
}

/// XYZ vertex normals of type `[f32; 3]`.
#[cfg(not(feature = "KHR_mesh_quantization"))]
pub type ReadNormals<'a> = Iter<'a, [f32; 3]>;

/// XYZ vertex normals as potentially quantized data
#[cfg(feature = "KHR_mesh_quantization")]
pub enum ReadNormals<'a> {
/// Position data of type I8
I8(Iter<'a, [i8; 3]>),
/// Position data of type I16
I16(Iter<'a, [i16; 3]>),
/// Position data of type F32
F32(Iter<'a, [f32; 3]>),
}

/// XYZW vertex tangents of type `[f32; 4]` where the `w` component is a
/// sign value (-1 or +1) indicating the handedness of the tangent basis.
#[cfg(not(feature = "KHR_mesh_quantization"))]
pub type ReadTangents<'a> = Iter<'a, [f32; 4]>;

/// XYZW vertex tangents of potentially quantized data where the `w` component is a
/// sign value (-1 or +1) indicating the handedness of the tangent basis.
#[cfg(feature = "KHR_mesh_quantization")]
pub enum ReadTangents<'a> {
/// Position data of type I8
I8(Iter<'a, [i8; 3]>),
/// Position data of type I16
I16(Iter<'a, [i16; 3]>),
/// Position data of type F32
F32(Iter<'a, [f32; 3]>),
}

/// XYZ vertex position displacements of type `[f32; 3]`.
pub type ReadPositionDisplacements<'a> = Iter<'a, [f32; 3]>;

Expand Down
2 changes: 1 addition & 1 deletion tests/import_sample_models.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::error::Error as StdError;
use std::{fs, path};

const SAMPLE_MODELS_DIRECTORY_PATH: &str = "glTF-Sample-Assets/Models";
const SAMPLE_MODELS_DIRECTORY_PATH: &str = "glTF-Sample-Models/2.0";

fn check_import_result(
result: gltf::Result<(
Expand Down
2 changes: 1 addition & 1 deletion tests/roundtrip_binary_gltf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use std::io::Read;
use std::{boxed, error, fs, io, path};

const SAMPLE_MODELS_DIRECTORY_PATH: &str = "glTF-Sample-Assets/Models";
const SAMPLE_MODELS_DIRECTORY_PATH: &str = "glTF-Sample-Models/2.0";

fn run() -> Result<(), boxed::Box<dyn error::Error>> {
let mut all_tests_passed = true;
Expand Down
20 changes: 19 additions & 1 deletion tests/test_wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::io::Read;
use std::{fs, io};

use gltf::mesh::util::ReadPositions;
use gltf::mesh::Bounds;

#[test]
Expand All @@ -27,7 +28,7 @@ fn test_accessor_bounds() {
/// The accessor use a base `bufferView` that contains 14 `Vec3`s and the sparse
/// section overwrites 3 of these with other values when read.
const SIMPLE_SPARSE_ACCESSOR_GLTF: &str =
"glTF-Sample-Assets/Models/SimpleSparseAccessor/glTF-Embedded/SimpleSparseAccessor.gltf";
"glTF-Sample-Models/2.0/SimpleSparseAccessor/glTF-Embedded/SimpleSparseAccessor.gltf";

#[test]
fn test_sparse_accessor_with_base_buffer_view_yield_exact_size_hints() {
Expand All @@ -37,8 +38,16 @@ fn test_sparse_accessor_with_base_buffer_view_yield_exact_size_hints() {
let primitive = mesh.primitives().next().unwrap();
let reader = primitive
.reader(|buffer: gltf::Buffer| buffers.get(buffer.index()).map(|data| &data.0[..]));

#[cfg(not(feature = "KHR_mesh_quantization"))]
let mut positions = reader.read_positions().unwrap();

#[cfg(feature = "KHR_mesh_quantization")]
let mut positions = match reader.read_positions().unwrap() {
ReadPositions::F32(iter) => iter,
_ => unreachable!("Meshes in gltf sample repo should not use quantization"),
};

const EXPECTED_POSITION_COUNT: usize = 14;
for i in (0..=EXPECTED_POSITION_COUNT).rev() {
assert_eq!(positions.size_hint(), (i, Some(i)));
Expand All @@ -54,8 +63,17 @@ fn test_sparse_accessor_with_base_buffer_view_yield_all_values() {
let primitive = mesh.primitives().next().unwrap();
let reader = primitive
.reader(|buffer: gltf::Buffer| buffers.get(buffer.index()).map(|data| &data.0[..]));

#[cfg(not(feature = "KHR_mesh_quantization"))]
let positions: Vec<[f32; 3]> = reader.read_positions().unwrap().collect::<Vec<_>>();

#[cfg(feature = "KHR_mesh_quantization")]
let positions = match reader.read_positions().unwrap() {
ReadPositions::F32(iter) => iter,
_ => unreachable!("Meshes in gltf sample repo should not use quantization"),
}
.collect::<Vec<_>>();

const EXPECTED_POSITIONS: [[f32; 3]; 14] = [
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
Expand Down

0 comments on commit 6dc0f3a

Please sign in to comment.