fyrox_impl/resource/gltf/
surface.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use crate::asset::core::math::TriangleDefinition;
22use crate::core::algebra::{Vector2, Vector3, Vector4};
23
24use crate::fxhash::FxHashMap;
25use crate::scene::mesh;
26use crate::scene::mesh::buffer::{
27    self, TriangleBuffer, ValidationError, VertexBuffer, VertexTrait,
28};
29use crate::scene::mesh::surface::{InputBlendShapeData, SurfaceData};
30use crate::scene::mesh::vertex::{AnimatedVertex, SimpleVertex, StaticVertex};
31use gltf::buffer::Buffer;
32use gltf::mesh::util::ReadJoints;
33use gltf::mesh::Mode;
34use gltf::mesh::Semantic;
35use gltf::Primitive;
36use half::f16;
37
38#[cfg(feature = "mesh_analysis")]
39use crate::{
40    core::math::Vector3Ext,
41    scene::mesh::buffer::{VertexAttributeUsage, VertexReadTrait},
42};
43
44use std::fmt::Display;
45use std::num::TryFromIntError;
46
47/// This type represents any error that may occur while importing mesh data from glTF.
48#[derive(Debug)]
49pub enum SurfaceDataError {
50    /// The mesh data had more vertex positions than some other vertex attributes.
51    /// For example, there might be positions for 10 vertices but normals for only 9 vertices.
52    CountMismatch,
53    /// The mesh vertex data in the glTF files does not include position vectors.
54    MissingPosition,
55    /// The mesh vertex data in the glTF files does not include normal vectors.
56    MissingNormal,
57    /// The mesh vertex data in the glTF files does not include UV coordinates.
58    MissingTexCoords,
59    /// The mesh vertex data in the glTF files does not include bone weight values.
60    MissingBoneWeight,
61    /// The mesh vertex data in the glTF files does not include bone index values.
62    MissingBoneIndex,
63    /// Bone indices in glTF format can be stored as u8 or u16, but Fyrox only supports
64    /// bone indices in u8. This error is produced if an index is found which does not fit
65    /// into u8.
66    InvalidBoneIndex,
67    /// The glTF format includes options for drawing points and lines, but this module
68    /// only supports drawing triangles.
69    InvalidMode,
70    /// An internal error in a glTF file. The glTF format uses indices to allow one
71    /// resource to reference another within the same file. This error indicates that
72    /// one of those indices was out-of-bounds. This should never happen.
73    InvalidIndex,
74    /// An error in converting u32 to usize, or from usize to u32.
75    Int(TryFromIntError),
76    /// Depending on the geometry type, certain numbers of vertices are errors.
77    /// For example, if the geometry is a list of triangles, then the number of vertices
78    /// needs to be a multiple of three. This error indicates a glTF file had the wrong
79    /// number of vertices in some mesh.
80    InvalidVertexCount(GeometryType, u32),
81    /// An error may occur while constructing a mesh buffer.
82    Validation(ValidationError),
83    /// An error may occur while writing mesh data.
84    Fetch(buffer::VertexFetchError),
85}
86
87impl std::error::Error for SurfaceDataError {}
88
89impl Display for SurfaceDataError {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        match self {
92            SurfaceDataError::CountMismatch => f.write_str("Count mismatch"),
93            SurfaceDataError::MissingPosition => f.write_str("Missing position"),
94            SurfaceDataError::MissingNormal => f.write_str("Missing normal"),
95            SurfaceDataError::MissingTexCoords => f.write_str("Missing texcoords"),
96            SurfaceDataError::MissingBoneWeight => f.write_str("Missing bone weight"),
97            SurfaceDataError::MissingBoneIndex => f.write_str("Missing bone index"),
98            SurfaceDataError::InvalidBoneIndex => f.write_str("Invalid bone index"),
99            SurfaceDataError::InvalidMode => f.write_str("Invalid mode"),
100            SurfaceDataError::InvalidIndex => f.write_str("Invalid index"),
101            SurfaceDataError::Int(error) => Display::fmt(error, f),
102            SurfaceDataError::InvalidVertexCount(geometry_type, count) => {
103                write!(f, "Cannot have {count} vertices {geometry_type}.")
104            }
105            SurfaceDataError::Validation(error) => Display::fmt(error, f),
106            SurfaceDataError::Fetch(error) => Display::fmt(error, f),
107        }
108    }
109}
110
111impl From<ValidationError> for SurfaceDataError {
112    fn from(error: ValidationError) -> Self {
113        SurfaceDataError::Validation(error)
114    }
115}
116
117impl From<TryFromIntError> for SurfaceDataError {
118    fn from(error: TryFromIntError) -> Self {
119        SurfaceDataError::Int(error)
120    }
121}
122
123impl From<buffer::VertexFetchError> for SurfaceDataError {
124    fn from(error: buffer::VertexFetchError) -> Self {
125        SurfaceDataError::Fetch(error)
126    }
127}
128
129#[derive(Debug)]
130pub enum GeometryType {
131    Triangles,
132    TriangleStrip,
133    TriangleFan,
134}
135
136impl Display for GeometryType {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        match self {
139            GeometryType::Triangles => f.write_str("triangles"),
140            GeometryType::TriangleStrip => f.write_str("triangle strip"),
141            GeometryType::TriangleFan => f.write_str("triangle fan"),
142        }
143    }
144}
145
146#[derive(Debug, Default, Clone)]
147pub struct BlendShapeInfo {
148    pub name: String,
149    pub default_weight: f32,
150}
151
152#[derive(Debug, Default, Clone)]
153pub struct BlendShapeInfoContainer {
154    names: Vec<String>,
155    weights: Vec<f32>,
156}
157
158impl BlendShapeInfoContainer {
159    pub fn new(names: Vec<String>, weights: Vec<f32>) -> Self {
160        BlendShapeInfoContainer { names, weights }
161    }
162    pub fn get(&self, index: usize) -> BlendShapeInfo {
163        BlendShapeInfo {
164            name: self
165                .names
166                .get(index)
167                .cloned()
168                .unwrap_or_else(|| index.to_string()),
169            default_weight: self.weights.get(index).cloned().unwrap_or(0.0),
170        }
171    }
172}
173
174#[derive(Debug, Copy, Clone)]
175pub struct GeometryStatistics {
176    pub min_edge_length_squared: f32,
177    pub repeated_index_count: usize,
178}
179
180impl GeometryStatistics {
181    #[cfg(feature = "mesh_analysis")]
182    pub fn update_length(&mut self, len: f32) {
183        if len < self.min_edge_length_squared {
184            self.min_edge_length_squared = len;
185        }
186    }
187    pub fn min_edge_length(&self) -> f32 {
188        self.min_edge_length_squared.sqrt()
189    }
190}
191
192impl Default for GeometryStatistics {
193    fn default() -> Self {
194        GeometryStatistics {
195            min_edge_length_squared: f32::INFINITY,
196            repeated_index_count: 0,
197        }
198    }
199}
200
201type Result<T> = std::result::Result<T, SurfaceDataError>;
202const DEFAULT_TANGENT: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 0.0);
203
204#[derive(Debug)]
205enum IndexData {
206    Buffer(Vec<u32>),
207    Direct(u32),
208}
209
210impl IndexData {
211    fn get_tri(&self, a: u32, b: u32, c: u32) -> Result<[u32; 3]> {
212        Ok([self.get(a)?, self.get(b)?, self.get(c)?])
213    }
214    fn get(&self, source_index: u32) -> Result<u32> {
215        match self {
216            IndexData::Buffer(data) => Ok(*data
217                .get(usize::try_from(source_index)?)
218                .ok_or(SurfaceDataError::InvalidIndex)?),
219            IndexData::Direct(size) if source_index < *size => Ok(source_index),
220            _ => Err(SurfaceDataError::InvalidIndex),
221        }
222    }
223    fn len(&self) -> Result<u32> {
224        match self {
225            IndexData::Buffer(data) => Ok(u32::try_from(data.len())?),
226            IndexData::Direct(size) => Ok(*size),
227        }
228    }
229}
230
231pub fn build_surface_data(
232    primitive: &Primitive,
233    morph_info: &BlendShapeInfoContainer,
234    buffers: &[Vec<u8>],
235    #[allow(unused_variables)] stats: &mut GeometryStatistics,
236) -> Result<Option<SurfaceData>> {
237    match primitive.mode() {
238        Mode::Points => {
239            return Ok(None);
240        }
241        Mode::Lines => {
242            return Ok(None);
243        }
244        Mode::LineLoop => {
245            return Ok(None);
246        }
247        Mode::LineStrip => {
248            return Ok(None);
249        }
250        Mode::Triangles => (),
251        Mode::TriangleStrip => (),
252        Mode::TriangleFan => (),
253    }
254    let vs: VertexBuffer = build_vertex_data(primitive, buffers)?;
255    let tris: TriangleBuffer = build_triangle_data(primitive, vs.vertex_count(), buffers)?;
256    #[cfg(feature = "mesh_analysis")]
257    update_statistics(&vs, &tris, stats)?;
258    let morphs: Vec<InputBlendShapeData> = build_morph_data(primitive, morph_info, buffers)?;
259    let mut surf = if !morphs.is_empty() {
260        let shapes = mesh::surface::BlendShapesContainer::from_lists(&vs, morphs.as_slice());
261        let mut surf = SurfaceData::new(vs, tris);
262        surf.blend_shapes_container = Some(shapes);
263        surf
264    } else {
265        SurfaceData::new(vs, tris)
266    };
267    let has_tex = primitive.get(&Semantic::TexCoords(0)).is_some();
268    let has_norm = primitive.get(&Semantic::Normals).is_some();
269    let has_tang = primitive.get(&Semantic::Tangents).is_some();
270    if has_tex && !has_norm {
271        surf.calculate_normals()?;
272        surf.calculate_tangents()?;
273    } else if has_tex && has_norm && !has_tang {
274        surf.calculate_tangents()?;
275    }
276    Ok(Some(surf))
277}
278
279#[cfg(feature = "mesh_analysis")]
280fn update_statistics(
281    vs: &VertexBuffer,
282    tris: &TriangleBuffer,
283    stats: &mut GeometryStatistics,
284) -> Result<()> {
285    for tri in tris.iter() {
286        if tri[0] == tri[1] || tri[1] == tri[2] || tri[0] == tri[2] {
287            stats.repeated_index_count += 1;
288        }
289        stats.update_length(edge_length_squared(tri[0], tri[1], vs)?);
290        stats.update_length(edge_length_squared(tri[1], tri[2], vs)?);
291        stats.update_length(edge_length_squared(tri[0], tri[2], vs)?);
292    }
293    Ok(())
294}
295
296#[cfg(feature = "mesh_analysis")]
297fn edge_length_squared(a: u32, b: u32, vs: &VertexBuffer) -> Result<f32> {
298    let a = usize::try_from(a)?;
299    let b = usize::try_from(b)?;
300    let a = vs.get(a).ok_or(SurfaceDataError::InvalidIndex)?;
301    let b = vs.get(b).ok_or(SurfaceDataError::InvalidIndex)?;
302    let a = a.read_3_f32(VertexAttributeUsage::Position)?;
303    let b = b.read_3_f32(VertexAttributeUsage::Position)?;
304    Ok(a.sqr_distance(&b))
305}
306
307fn build_morph_data(
308    primitive: &Primitive,
309    morph_info: &BlendShapeInfoContainer,
310    buffers: &[Vec<u8>],
311) -> Result<Vec<InputBlendShapeData>> {
312    inner_build_morph_data(primitive, morph_info, buffers)
313}
314
315fn inner_build_morph_data(
316    primitive: &Primitive,
317    morph_info: &BlendShapeInfoContainer,
318    buffers: &[Vec<u8>],
319) -> Result<Vec<InputBlendShapeData>> {
320    let reader = primitive.reader(|buf: Buffer| buffers.get(buf.index()).map(Vec::as_slice));
321    let reader = reader.read_morph_targets();
322    let mut result: Vec<InputBlendShapeData> = Vec::new();
323    for (i, (pos, norm, tang)) in reader.enumerate() {
324        let info = morph_info.get(i);
325        let positions = if let Some(iter) = pos {
326            iter_to_map(iter)
327        } else {
328            FxHashMap::default()
329        };
330        let normals = if let Some(iter) = norm {
331            iter_to_map(iter)
332        } else {
333            FxHashMap::default()
334        };
335        let tangents = if let Some(iter) = tang {
336            iter_to_map(iter)
337        } else {
338            FxHashMap::default()
339        };
340        result.push(InputBlendShapeData {
341            default_weight: info.default_weight,
342            name: info.name,
343            positions,
344            normals,
345            tangents,
346        });
347    }
348    Ok(result)
349}
350
351fn iter_to_map<I>(iter: I) -> FxHashMap<u32, Vector3<f16>>
352where
353    I: Iterator<Item = [f32; 3]>,
354{
355    let mut map: FxHashMap<u32, Vector3<f16>> = FxHashMap::default();
356    for (i, v) in iter.enumerate() {
357        if v == [0.0; 3] {
358            continue;
359        }
360        if let Ok(index) = u32::try_from(i) {
361            let v: [f16; 3] = v.map(f16::from_f32);
362            map.insert(index, Vector3::<f16>::from(v));
363        }
364    }
365    map
366}
367
368fn build_vertex_data(primitive: &Primitive, buffers: &[Vec<u8>]) -> Result<VertexBuffer> {
369    build_vertex_data_with(primitive, |buf: Buffer| {
370        buffers.get(buf.index()).map(Vec::as_slice)
371    })
372}
373
374fn build_triangle_data(
375    primitive: &Primitive,
376    vertex_count: u32,
377    buffers: &[Vec<u8>],
378) -> Result<TriangleBuffer> {
379    let reader = primitive.reader(|buf: Buffer| buffers.get(buf.index()).map(Vec::as_slice));
380    let index_data = match reader.read_indices() {
381        Some(index_reader) => IndexData::Buffer(index_reader.into_u32().collect()),
382        None => IndexData::Direct(vertex_count),
383    };
384    let tris: Vec<TriangleDefinition> = (match primitive.mode() {
385        Mode::Points => Err(SurfaceDataError::InvalidMode),
386        Mode::Lines => Err(SurfaceDataError::InvalidMode),
387        Mode::LineLoop => Err(SurfaceDataError::InvalidMode),
388        Mode::LineStrip => Err(SurfaceDataError::InvalidMode),
389        Mode::Triangles => build_triangles(&index_data),
390        Mode::TriangleStrip => build_triangle_strip(&index_data),
391        Mode::TriangleFan => build_triangle_fan(&index_data),
392    })?;
393    Ok(TriangleBuffer::new(tris))
394}
395
396fn build_triangles(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
397    let vertex_count = data.len()?;
398    if vertex_count == 0 || vertex_count % 3 != 0 {
399        return Err(SurfaceDataError::InvalidVertexCount(
400            GeometryType::Triangles,
401            vertex_count,
402        ));
403    }
404    let tri_count: u32 = vertex_count / 3;
405    let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
406    for i in 0..tri_count {
407        let v: u32 = i * 3;
408        tris.push(TriangleDefinition(data.get_tri(v, v + 1, v + 2)?));
409    }
410    Ok(tris)
411}
412fn build_triangle_strip(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
413    let vertex_count = data.len()?;
414    if vertex_count < 3 {
415        return Err(SurfaceDataError::InvalidVertexCount(
416            GeometryType::TriangleStrip,
417            vertex_count,
418        ));
419    }
420    let tri_count: u32 = vertex_count - 2;
421    let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
422    for i in 0..tri_count {
423        let odd = i % 2;
424        tris.push(TriangleDefinition(data.get_tri(
425            i,
426            i + 1 + odd,
427            i + 2 - odd,
428        )?));
429    }
430    Ok(tris)
431}
432fn build_triangle_fan(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
433    let vertex_count = data.len()?;
434    if vertex_count < 3 {
435        return Err(SurfaceDataError::InvalidVertexCount(
436            GeometryType::TriangleFan,
437            vertex_count,
438        ));
439    }
440    let tri_count: u32 = vertex_count - 2;
441    let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
442    for i in 0..tri_count {
443        tris.push(TriangleDefinition(data.get_tri(i + 1, i + 2, 0)?));
444    }
445    Ok(tris)
446}
447
448fn build_vertex_data_with<'a, 's, F>(
449    primitive: &'a Primitive,
450    get_buffer_data: F,
451) -> Result<VertexBuffer>
452where
453    F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
454{
455    let reader = primitive.reader(get_buffer_data.clone());
456    if reader.read_weights(0).is_some() {
457        let vs: Vec<AnimatedVertex> = AnimatedVertex::convert(primitive, get_buffer_data)?;
458        Ok(VertexBuffer::new(vs.len(), vs)?)
459    } else if reader.read_normals().is_some() {
460        let vs: Vec<StaticVertex> = StaticVertex::convert(primitive, get_buffer_data)?;
461        Ok(VertexBuffer::new(vs.len(), vs)?)
462    } else {
463        let vs: Vec<SimpleVertex> = SimpleVertex::convert(primitive, get_buffer_data)?;
464        Ok(VertexBuffer::new(vs.len(), vs)?)
465    }
466}
467
468trait GltfVertexConvert: VertexTrait {
469    fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
470    where
471        F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>;
472}
473
474impl GltfVertexConvert for SimpleVertex {
475    fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
476    where
477        F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
478    {
479        let reader = primitive.reader(get_buffer_data);
480        if let Some(iter) = reader.read_positions() {
481            Ok(iter
482                .map(Vector3::from)
483                .map(|v| SimpleVertex { position: v })
484                .collect())
485        } else {
486            Err(SurfaceDataError::MissingPosition)
487        }
488    }
489}
490
491impl GltfVertexConvert for StaticVertex {
492    fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
493    where
494        F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
495    {
496        let reader = primitive.reader(get_buffer_data);
497        let pos_iter = reader
498            .read_positions()
499            .ok_or(SurfaceDataError::MissingPosition)?;
500        let mut norm_iter = reader
501            .read_normals()
502            .ok_or(SurfaceDataError::MissingNormal)?;
503        let mut tang_iter = reader.read_tangents();
504        let mut uv_iter = reader
505            .read_tex_coords(0)
506            .ok_or(SurfaceDataError::MissingTexCoords)?
507            .into_f32();
508        let mut result: Vec<StaticVertex> = Vec::with_capacity(pos_iter.len());
509        for pos in pos_iter {
510            let pos: Vector3<f32> = Vector3::from(pos);
511            let norm: Option<Vector3<f32>> = norm_iter.next().map(Vector3::from);
512            let uv: Option<Vector2<f32>> = uv_iter.next().map(Vector2::from);
513            let tang: Option<Vector4<f32>> = if let Some(iter) = tang_iter.as_mut() {
514                iter.next().map(Vector4::from)
515            } else {
516                Some(DEFAULT_TANGENT)
517            };
518            if let (Some(normal), Some(tex_coord), Some(tangent)) = (norm, uv, tang) {
519                result.push(StaticVertex {
520                    position: pos,
521                    normal,
522                    tex_coord,
523                    tangent,
524                });
525            } else {
526                return Err(SurfaceDataError::CountMismatch);
527            }
528        }
529        Ok(result)
530    }
531}
532
533impl GltfVertexConvert for AnimatedVertex {
534    fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
535    where
536        F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
537    {
538        let reader = primitive.reader(get_buffer_data);
539        let pos_iter = reader
540            .read_positions()
541            .ok_or(SurfaceDataError::MissingPosition)?;
542        let mut norm_iter = reader
543            .read_normals()
544            .ok_or(SurfaceDataError::MissingNormal)?;
545        let mut tang_iter = reader.read_tangents();
546        let mut uv_iter = reader
547            .read_tex_coords(0)
548            .ok_or(SurfaceDataError::MissingTexCoords)?
549            .into_f32();
550        let mut wgt_iter = reader
551            .read_weights(0)
552            .ok_or(SurfaceDataError::MissingBoneWeight)?
553            .into_f32();
554        let mut jnt_iter = reader
555            .read_joints(0)
556            .ok_or(SurfaceDataError::MissingBoneIndex)?;
557        let mut result: Vec<AnimatedVertex> = Vec::with_capacity(pos_iter.len());
558        for pos in pos_iter {
559            let pos: Vector3<f32> = Vector3::from(pos);
560            let norm: Option<Vector3<f32>> = norm_iter.next().map(Vector3::from);
561            let uv: Option<Vector2<f32>> = uv_iter.next().map(Vector2::from);
562            let bone_weights: Option<[f32; 4]> = wgt_iter.next();
563            let bone_indices: Option<[u8; 4]> = read_valid_index(&mut jnt_iter)?;
564            let tang: Option<Vector4<f32>> = if let Some(iter) = tang_iter.as_mut() {
565                iter.next().map(Vector4::from)
566            } else {
567                Some(DEFAULT_TANGENT)
568            };
569            if let (
570                Some(normal),
571                Some(tex_coord),
572                Some(tangent),
573                Some(bone_weights),
574                Some(bone_indices),
575            ) = (norm, uv, tang, bone_weights, bone_indices)
576            {
577                result.push(AnimatedVertex {
578                    position: pos,
579                    normal,
580                    tex_coord,
581                    tangent,
582                    bone_weights,
583                    bone_indices,
584                });
585            } else {
586                return Err(SurfaceDataError::CountMismatch);
587            }
588        }
589        Ok(result)
590    }
591}
592
593fn read_valid_index(reader: &mut ReadJoints) -> Result<Option<[u8; 4]>> {
594    match reader {
595        ReadJoints::U8(iter) => Ok(iter.next()),
596        ReadJoints::U16(iter) => {
597            if let Some(value) = iter.next() {
598                let mut result: [u8; 4] = [0; 4];
599                for (i, v) in value.iter().enumerate() {
600                    result[i] = u8::try_from(*v).or(Err(SurfaceDataError::InvalidBoneIndex))?;
601                }
602                Ok(Some(result))
603            } else {
604                Ok(None)
605            }
606        }
607    }
608}