Skip to main content

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 bone weight values.
56    MissingBoneWeight,
57    /// The mesh vertex data in the glTF files does not include bone index values.
58    MissingBoneIndex,
59    /// Bone indices in glTF format can be stored as u8 or u16, but Fyrox only supports
60    /// bone indices in u8. This error is produced if an index is found which does not fit
61    /// into u8.
62    InvalidBoneIndex,
63    /// The glTF format includes options for drawing points and lines, but this module
64    /// only supports drawing triangles.
65    InvalidMode,
66    /// An internal error in a glTF file. The glTF format uses indices to allow one
67    /// resource to reference another within the same file. This error indicates that
68    /// one of those indices was out-of-bounds. This should never happen.
69    InvalidIndex,
70    /// An error in converting u32 to usize, or from usize to u32.
71    Int(TryFromIntError),
72    /// Depending on the geometry type, certain numbers of vertices are errors.
73    /// For example, if the geometry is a list of triangles, then the number of vertices
74    /// needs to be a multiple of three. This error indicates a glTF file had the wrong
75    /// number of vertices in some mesh.
76    InvalidVertexCount(GeometryType, u32),
77    /// An error may occur while constructing a mesh buffer.
78    Validation(ValidationError),
79    /// An error may occur while writing mesh data.
80    Fetch(buffer::VertexFetchError),
81}
82
83impl std::error::Error for SurfaceDataError {}
84
85impl Display for SurfaceDataError {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        match self {
88            SurfaceDataError::CountMismatch => f.write_str("Count mismatch"),
89            SurfaceDataError::MissingPosition => f.write_str("Missing position"),
90            SurfaceDataError::MissingBoneWeight => f.write_str("Missing bone weight"),
91            SurfaceDataError::MissingBoneIndex => f.write_str("Missing bone index"),
92            SurfaceDataError::InvalidBoneIndex => f.write_str("Invalid bone index"),
93            SurfaceDataError::InvalidMode => f.write_str("Invalid mode"),
94            SurfaceDataError::InvalidIndex => f.write_str("Invalid index"),
95            SurfaceDataError::Int(error) => Display::fmt(error, f),
96            SurfaceDataError::InvalidVertexCount(geometry_type, count) => {
97                write!(f, "Cannot have {count} vertices {geometry_type}.")
98            }
99            SurfaceDataError::Validation(error) => Display::fmt(error, f),
100            SurfaceDataError::Fetch(error) => Display::fmt(error, f),
101        }
102    }
103}
104
105impl From<ValidationError> for SurfaceDataError {
106    fn from(error: ValidationError) -> Self {
107        SurfaceDataError::Validation(error)
108    }
109}
110
111impl From<TryFromIntError> for SurfaceDataError {
112    fn from(error: TryFromIntError) -> Self {
113        SurfaceDataError::Int(error)
114    }
115}
116
117impl From<buffer::VertexFetchError> for SurfaceDataError {
118    fn from(error: buffer::VertexFetchError) -> Self {
119        SurfaceDataError::Fetch(error)
120    }
121}
122
123#[derive(Debug)]
124pub enum GeometryType {
125    Triangles,
126    TriangleStrip,
127    TriangleFan,
128}
129
130impl Display for GeometryType {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        match self {
133            GeometryType::Triangles => f.write_str("triangles"),
134            GeometryType::TriangleStrip => f.write_str("triangle strip"),
135            GeometryType::TriangleFan => f.write_str("triangle fan"),
136        }
137    }
138}
139
140#[derive(Debug, Default, Clone)]
141pub struct BlendShapeInfo {
142    pub name: String,
143    pub default_weight: f32,
144}
145
146#[derive(Debug, Default, Clone)]
147pub struct BlendShapeInfoContainer {
148    names: Vec<String>,
149    weights: Vec<f32>,
150}
151
152impl BlendShapeInfoContainer {
153    pub fn new(names: Vec<String>, weights: Vec<f32>) -> Self {
154        BlendShapeInfoContainer { names, weights }
155    }
156    pub fn get(&self, index: usize) -> BlendShapeInfo {
157        BlendShapeInfo {
158            name: self
159                .names
160                .get(index)
161                .cloned()
162                .unwrap_or_else(|| index.to_string()),
163            default_weight: self.weights.get(index).cloned().unwrap_or(0.0),
164        }
165    }
166}
167
168#[derive(Debug, Copy, Clone)]
169pub struct GeometryStatistics {
170    pub min_edge_length_squared: f32,
171    pub repeated_index_count: usize,
172}
173
174impl GeometryStatistics {
175    #[cfg(feature = "mesh_analysis")]
176    pub fn update_length(&mut self, len: f32) {
177        if len < self.min_edge_length_squared {
178            self.min_edge_length_squared = len;
179        }
180    }
181    pub fn min_edge_length(&self) -> f32 {
182        self.min_edge_length_squared.sqrt()
183    }
184}
185
186impl Default for GeometryStatistics {
187    fn default() -> Self {
188        GeometryStatistics {
189            min_edge_length_squared: f32::INFINITY,
190            repeated_index_count: 0,
191        }
192    }
193}
194
195type Result<T> = std::result::Result<T, SurfaceDataError>;
196const DEFAULT_TANGENT: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 0.0);
197
198#[derive(Debug)]
199enum IndexData {
200    Buffer(Vec<u32>),
201    Direct(u32),
202}
203
204impl IndexData {
205    fn get_tri(&self, a: u32, b: u32, c: u32) -> Result<[u32; 3]> {
206        Ok([self.get(a)?, self.get(b)?, self.get(c)?])
207    }
208    fn get(&self, source_index: u32) -> Result<u32> {
209        match self {
210            IndexData::Buffer(data) => Ok(*data
211                .get(usize::try_from(source_index)?)
212                .ok_or(SurfaceDataError::InvalidIndex)?),
213            IndexData::Direct(size) if source_index < *size => Ok(source_index),
214            _ => Err(SurfaceDataError::InvalidIndex),
215        }
216    }
217    fn len(&self) -> Result<u32> {
218        match self {
219            IndexData::Buffer(data) => Ok(u32::try_from(data.len())?),
220            IndexData::Direct(size) => Ok(*size),
221        }
222    }
223}
224
225pub fn build_surface_data(
226    primitive: &Primitive,
227    morph_info: &BlendShapeInfoContainer,
228    buffers: &[Vec<u8>],
229    #[allow(unused_variables)] stats: &mut GeometryStatistics,
230) -> Result<Option<SurfaceData>> {
231    match primitive.mode() {
232        Mode::Points => {
233            return Ok(None);
234        }
235        Mode::Lines => {
236            return Ok(None);
237        }
238        Mode::LineLoop => {
239            return Ok(None);
240        }
241        Mode::LineStrip => {
242            return Ok(None);
243        }
244        Mode::Triangles => (),
245        Mode::TriangleStrip => (),
246        Mode::TriangleFan => (),
247    }
248    let vs: VertexBuffer = build_vertex_data(primitive, buffers)?;
249    let tris: TriangleBuffer = build_triangle_data(primitive, vs.vertex_count(), buffers)?;
250    #[cfg(feature = "mesh_analysis")]
251    update_statistics(&vs, &tris, stats)?;
252    let morphs: Vec<InputBlendShapeData> = build_morph_data(primitive, morph_info, buffers)?;
253    let mut surf = if !morphs.is_empty() {
254        let shapes = mesh::surface::BlendShapesContainer::from_lists(&vs, morphs.as_slice());
255        let mut surf = SurfaceData::new(vs, tris);
256        surf.blend_shapes_container = Some(shapes);
257        surf
258    } else {
259        SurfaceData::new(vs, tris)
260    };
261    let has_tex = primitive.get(&Semantic::TexCoords(0)).is_some();
262    let has_norm = primitive.get(&Semantic::Normals).is_some();
263    let has_tang = primitive.get(&Semantic::Tangents).is_some();
264    if has_tex && !has_norm {
265        surf.calculate_normals()?;
266        surf.calculate_tangents()?;
267    } else if has_tex && has_norm && !has_tang {
268        surf.calculate_tangents()?;
269    }
270    Ok(Some(surf))
271}
272
273#[cfg(feature = "mesh_analysis")]
274fn update_statistics(
275    vs: &VertexBuffer,
276    tris: &TriangleBuffer,
277    stats: &mut GeometryStatistics,
278) -> Result<()> {
279    for tri in tris.iter() {
280        if tri[0] == tri[1] || tri[1] == tri[2] || tri[0] == tri[2] {
281            stats.repeated_index_count += 1;
282        }
283        stats.update_length(edge_length_squared(tri[0], tri[1], vs)?);
284        stats.update_length(edge_length_squared(tri[1], tri[2], vs)?);
285        stats.update_length(edge_length_squared(tri[0], tri[2], vs)?);
286    }
287    Ok(())
288}
289
290#[cfg(feature = "mesh_analysis")]
291fn edge_length_squared(a: u32, b: u32, vs: &VertexBuffer) -> Result<f32> {
292    let a = usize::try_from(a)?;
293    let b = usize::try_from(b)?;
294    let a = vs.get(a).ok_or(SurfaceDataError::InvalidIndex)?;
295    let b = vs.get(b).ok_or(SurfaceDataError::InvalidIndex)?;
296    let a = a.read_3_f32(VertexAttributeUsage::Position)?;
297    let b = b.read_3_f32(VertexAttributeUsage::Position)?;
298    Ok(a.sqr_distance(&b))
299}
300
301fn build_morph_data(
302    primitive: &Primitive,
303    morph_info: &BlendShapeInfoContainer,
304    buffers: &[Vec<u8>],
305) -> Result<Vec<InputBlendShapeData>> {
306    inner_build_morph_data(primitive, morph_info, buffers)
307}
308
309fn inner_build_morph_data(
310    primitive: &Primitive,
311    morph_info: &BlendShapeInfoContainer,
312    buffers: &[Vec<u8>],
313) -> Result<Vec<InputBlendShapeData>> {
314    let reader = primitive.reader(|buf: Buffer| buffers.get(buf.index()).map(Vec::as_slice));
315    let reader = reader.read_morph_targets();
316    let mut result: Vec<InputBlendShapeData> = Vec::new();
317    for (i, (pos, norm, tang)) in reader.enumerate() {
318        let info = morph_info.get(i);
319        let positions = if let Some(iter) = pos {
320            iter_to_map(iter)
321        } else {
322            FxHashMap::default()
323        };
324        let normals = if let Some(iter) = norm {
325            iter_to_map(iter)
326        } else {
327            FxHashMap::default()
328        };
329        let tangents = if let Some(iter) = tang {
330            iter_to_map(iter)
331        } else {
332            FxHashMap::default()
333        };
334        result.push(InputBlendShapeData {
335            default_weight: info.default_weight,
336            name: info.name,
337            positions,
338            normals,
339            tangents,
340        });
341    }
342    Ok(result)
343}
344
345fn iter_to_map<I>(iter: I) -> FxHashMap<u32, Vector3<f16>>
346where
347    I: Iterator<Item = [f32; 3]>,
348{
349    let mut map: FxHashMap<u32, Vector3<f16>> = FxHashMap::default();
350    for (i, v) in iter.enumerate() {
351        if v == [0.0; 3] {
352            continue;
353        }
354        if let Ok(index) = u32::try_from(i) {
355            let v: [f16; 3] = v.map(f16::from_f32);
356            map.insert(index, Vector3::<f16>::from(v));
357        }
358    }
359    map
360}
361
362fn build_vertex_data(primitive: &Primitive, buffers: &[Vec<u8>]) -> Result<VertexBuffer> {
363    build_vertex_data_with(primitive, |buf: Buffer| {
364        buffers.get(buf.index()).map(Vec::as_slice)
365    })
366}
367
368fn build_triangle_data(
369    primitive: &Primitive,
370    vertex_count: u32,
371    buffers: &[Vec<u8>],
372) -> Result<TriangleBuffer> {
373    let reader = primitive.reader(|buf: Buffer| buffers.get(buf.index()).map(Vec::as_slice));
374    let index_data = match reader.read_indices() {
375        Some(index_reader) => IndexData::Buffer(index_reader.into_u32().collect()),
376        None => IndexData::Direct(vertex_count),
377    };
378    let tris: Vec<TriangleDefinition> = (match primitive.mode() {
379        Mode::Points => Err(SurfaceDataError::InvalidMode),
380        Mode::Lines => Err(SurfaceDataError::InvalidMode),
381        Mode::LineLoop => Err(SurfaceDataError::InvalidMode),
382        Mode::LineStrip => Err(SurfaceDataError::InvalidMode),
383        Mode::Triangles => build_triangles(&index_data),
384        Mode::TriangleStrip => build_triangle_strip(&index_data),
385        Mode::TriangleFan => build_triangle_fan(&index_data),
386    })?;
387    Ok(TriangleBuffer::new(tris))
388}
389
390fn build_triangles(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
391    let vertex_count = data.len()?;
392    if vertex_count == 0 || vertex_count % 3 != 0 {
393        return Err(SurfaceDataError::InvalidVertexCount(
394            GeometryType::Triangles,
395            vertex_count,
396        ));
397    }
398    let tri_count: u32 = vertex_count / 3;
399    let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
400    for i in 0..tri_count {
401        let v: u32 = i * 3;
402        tris.push(TriangleDefinition(data.get_tri(v, v + 1, v + 2)?));
403    }
404    Ok(tris)
405}
406fn build_triangle_strip(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
407    let vertex_count = data.len()?;
408    if vertex_count < 3 {
409        return Err(SurfaceDataError::InvalidVertexCount(
410            GeometryType::TriangleStrip,
411            vertex_count,
412        ));
413    }
414    let tri_count: u32 = vertex_count - 2;
415    let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
416    for i in 0..tri_count {
417        let odd = i % 2;
418        tris.push(TriangleDefinition(data.get_tri(
419            i,
420            i + 1 + odd,
421            i + 2 - odd,
422        )?));
423    }
424    Ok(tris)
425}
426fn build_triangle_fan(data: &IndexData) -> Result<Vec<TriangleDefinition>> {
427    let vertex_count = data.len()?;
428    if vertex_count < 3 {
429        return Err(SurfaceDataError::InvalidVertexCount(
430            GeometryType::TriangleFan,
431            vertex_count,
432        ));
433    }
434    let tri_count: u32 = vertex_count - 2;
435    let mut tris: Vec<TriangleDefinition> = Vec::with_capacity(tri_count as usize);
436    for i in 0..tri_count {
437        tris.push(TriangleDefinition(data.get_tri(i + 1, i + 2, 0)?));
438    }
439    Ok(tris)
440}
441
442fn build_vertex_data_with<'a, 's, F>(
443    primitive: &'a Primitive,
444    get_buffer_data: F,
445) -> Result<VertexBuffer>
446where
447    F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
448{
449    let reader = primitive.reader(get_buffer_data.clone());
450    if reader.read_weights(0).is_some() {
451        let vs: Vec<AnimatedVertex> = AnimatedVertex::convert(primitive, get_buffer_data)?;
452        Ok(VertexBuffer::new(vs.len(), vs)?)
453    } else if reader.read_normals().is_some() {
454        let vs: Vec<StaticVertex> = StaticVertex::convert(primitive, get_buffer_data)?;
455        Ok(VertexBuffer::new(vs.len(), vs)?)
456    } else {
457        let vs: Vec<SimpleVertex> = SimpleVertex::convert(primitive, get_buffer_data)?;
458        Ok(VertexBuffer::new(vs.len(), vs)?)
459    }
460}
461
462trait GltfVertexConvert: VertexTrait {
463    fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
464    where
465        F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>;
466}
467
468impl GltfVertexConvert for SimpleVertex {
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        let reader = primitive.reader(get_buffer_data);
474        if let Some(iter) = reader.read_positions() {
475            Ok(iter
476                .map(Vector3::from)
477                .map(|v| SimpleVertex { position: v })
478                .collect())
479        } else {
480            Err(SurfaceDataError::MissingPosition)
481        }
482    }
483}
484
485impl GltfVertexConvert for StaticVertex {
486    fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
487    where
488        F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
489    {
490        let reader = primitive.reader(get_buffer_data);
491        let pos_iter = reader
492            .read_positions()
493            .ok_or(SurfaceDataError::MissingPosition)?;
494        let mut norm_iter = reader.read_normals();
495        let mut tang_iter = reader.read_tangents();
496        let mut uv_iter = reader.read_tex_coords(0).map(|i| i.into_f32());
497        let mut result: Vec<StaticVertex> = Vec::with_capacity(pos_iter.len());
498        for pos in pos_iter {
499            let pos: Vector3<f32> = Vector3::from(pos);
500            let norm: Option<Vector3<f32>> = if let Some(iter) = norm_iter.as_mut() {
501                iter.next().map(Vector3::from)
502            } else {
503                Some(Vector3::new(0.0, 1.0, 0.0))
504            };
505            let uv: Option<Vector2<f32>> = if let Some(iter) = uv_iter.as_mut() {
506                iter.next().map(Vector2::from)
507            } else {
508                Some(Vector2::repeat(0.0))
509            };
510            let tang: Option<Vector4<f32>> = if let Some(iter) = tang_iter.as_mut() {
511                iter.next().map(Vector4::from)
512            } else {
513                Some(DEFAULT_TANGENT)
514            };
515            if let (Some(normal), Some(tex_coord), Some(tangent)) = (norm, uv, tang) {
516                result.push(StaticVertex {
517                    position: pos,
518                    normal,
519                    tex_coord,
520                    tangent,
521                });
522            } else {
523                return Err(SurfaceDataError::CountMismatch);
524            }
525        }
526        Ok(result)
527    }
528}
529
530impl GltfVertexConvert for AnimatedVertex {
531    fn convert<'a, 's, F>(primitive: &'a Primitive, get_buffer_data: F) -> Result<Vec<Self>>
532    where
533        F: Clone + Fn(Buffer<'a>) -> Option<&'s [u8]>,
534    {
535        let reader = primitive.reader(get_buffer_data);
536        let pos_iter = reader
537            .read_positions()
538            .ok_or(SurfaceDataError::MissingPosition)?;
539        let mut norm_iter = reader.read_normals();
540        let mut tang_iter = reader.read_tangents();
541        let mut uv_iter = reader.read_tex_coords(0).map(|i| i.into_f32());
542        let mut wgt_iter = reader
543            .read_weights(0)
544            .ok_or(SurfaceDataError::MissingBoneWeight)?
545            .into_f32();
546        let mut jnt_iter = reader
547            .read_joints(0)
548            .ok_or(SurfaceDataError::MissingBoneIndex)?;
549        let mut result: Vec<AnimatedVertex> = Vec::with_capacity(pos_iter.len());
550        for pos in pos_iter {
551            let pos: Vector3<f32> = Vector3::from(pos);
552            let norm: Option<Vector3<f32>> = if let Some(iter) = norm_iter.as_mut() {
553                iter.next().map(Vector3::from)
554            } else {
555                Some(Vector3::new(0.0, 1.0, 0.0))
556            };
557            let uv: Option<Vector2<f32>> = if let Some(iter) = uv_iter.as_mut() {
558                iter.next().map(Vector2::from)
559            } else {
560                Some(Vector2::repeat(0.0))
561            };
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}