rg3d/resource/fbx/scene/
geometry.rs

1use crate::core::algebra::{Vector2, Vector3};
2use crate::{
3    core::pool::Handle,
4    resource::{
5        fbx::scene,
6        fbx::{
7            document::{FbxNode, FbxNodeContainer},
8            error::FbxError,
9            scene::{FbxComponent, FbxContainer, FbxScene},
10        },
11    },
12    scene::mesh::surface::{VertexWeight, VertexWeightSet},
13};
14
15pub struct FbxGeometry {
16    // Only vertices and indices are required.
17    pub vertices: Vec<Vector3<f32>>,
18    pub indices: Vec<i32>,
19
20    // Normals, UVs, etc. are optional.
21    pub normals: Option<FbxContainer<Vector3<f32>>>,
22    pub uvs: Option<FbxContainer<Vector2<f32>>>,
23    pub materials: Option<FbxContainer<i32>>,
24    pub tangents: Option<FbxContainer<Vector3<f32>>>,
25    pub binormals: Option<FbxContainer<Vector3<f32>>>,
26
27    pub deformers: Vec<Handle<FbxComponent>>,
28}
29
30fn read_vertices(
31    geom_node_handle: Handle<FbxNode>,
32    nodes: &FbxNodeContainer,
33) -> Result<Vec<Vector3<f32>>, FbxError> {
34    let vertices_node_handle = nodes.find(geom_node_handle, "Vertices")?;
35    let vertices_array_node = nodes.get_by_name(vertices_node_handle, "a")?;
36    let mut vertices = Vec::with_capacity(vertices_array_node.attrib_count() / 3);
37    for vertex in vertices_array_node.attributes().chunks_exact(3) {
38        vertices.push(Vector3::new(
39            vertex[0].as_f32()?,
40            vertex[1].as_f32()?,
41            vertex[2].as_f32()?,
42        ));
43    }
44
45    Ok(vertices)
46}
47
48fn read_indices(
49    geom_node_handle: Handle<FbxNode>,
50    nodes: &FbxNodeContainer,
51) -> Result<Vec<i32>, FbxError> {
52    let indices_node_handle = nodes.find(geom_node_handle, "PolygonVertexIndex")?;
53    let indices_array_node = nodes.get_by_name(indices_node_handle, "a")?;
54    let mut indices = Vec::with_capacity(indices_array_node.attrib_count());
55    for index in indices_array_node.attributes() {
56        indices.push(index.as_i32()?);
57    }
58    Ok(indices)
59}
60
61fn read_normals(
62    geom_node_handle: Handle<FbxNode>,
63    nodes: &FbxNodeContainer,
64) -> Result<Option<FbxContainer<Vector3<f32>>>, FbxError> {
65    if let Ok(layer_element_normal) = nodes.find(geom_node_handle, "LayerElementNormal") {
66        Ok(Some(scene::make_vec3_container(
67            nodes,
68            layer_element_normal,
69            "Normals",
70        )?))
71    } else {
72        Ok(None)
73    }
74}
75
76fn read_tangents(
77    geom_node_handle: Handle<FbxNode>,
78    nodes: &FbxNodeContainer,
79) -> Result<Option<FbxContainer<Vector3<f32>>>, FbxError> {
80    if let Ok(layer_element_tangent) = nodes.find(geom_node_handle, "LayerElementTangent") {
81        Ok(Some(scene::make_vec3_container(
82            nodes,
83            layer_element_tangent,
84            "Tangents",
85        )?))
86    } else {
87        Ok(None)
88    }
89}
90
91fn read_binormals(
92    geom_node_handle: Handle<FbxNode>,
93    nodes: &FbxNodeContainer,
94) -> Result<Option<FbxContainer<Vector3<f32>>>, FbxError> {
95    if let Ok(layer_element_tangent) = nodes.find(geom_node_handle, "LayerElementBinormal") {
96        Ok(Some(scene::make_vec3_container(
97            nodes,
98            layer_element_tangent,
99            "Binormals",
100        )?))
101    } else {
102        Ok(None)
103    }
104}
105
106fn read_uvs(
107    geom_node_handle: Handle<FbxNode>,
108    nodes: &FbxNodeContainer,
109) -> Result<Option<FbxContainer<Vector2<f32>>>, FbxError> {
110    if let Ok(layer_element_uv) = nodes.find(geom_node_handle, "LayerElementUV") {
111        Ok(Some(FbxContainer::new(
112            nodes,
113            layer_element_uv,
114            "UV",
115            |attributes| {
116                let mut uvs = Vec::with_capacity(attributes.len() / 2);
117                for uv in attributes.chunks_exact(2) {
118                    uvs.push(Vector2::new(uv[0].as_f32()?, uv[1].as_f32()?));
119                }
120                Ok(uvs)
121            },
122        )?))
123    } else {
124        Ok(None)
125    }
126}
127
128fn read_materials(
129    geom_node_handle: Handle<FbxNode>,
130    nodes: &FbxNodeContainer,
131) -> Result<Option<FbxContainer<i32>>, FbxError> {
132    if let Ok(layer_element_material_node_handle) =
133        nodes.find(geom_node_handle, "LayerElementMaterial")
134    {
135        Ok(Some(FbxContainer::new(
136            nodes,
137            layer_element_material_node_handle,
138            "Materials",
139            |attributes| {
140                let mut materials = Vec::with_capacity(attributes.len());
141                for attribute in attributes {
142                    materials.push(attribute.as_i32()?);
143                }
144                Ok(materials)
145            },
146        )?))
147    } else {
148        Ok(None)
149    }
150}
151
152impl FbxGeometry {
153    pub(in crate::resource::fbx) fn read(
154        geom_node_handle: Handle<FbxNode>,
155        nodes: &FbxNodeContainer,
156    ) -> Result<FbxGeometry, FbxError> {
157        Ok(FbxGeometry {
158            vertices: read_vertices(geom_node_handle, nodes)?,
159            indices: read_indices(geom_node_handle, nodes)?,
160            normals: read_normals(geom_node_handle, nodes)?,
161            uvs: read_uvs(geom_node_handle, nodes)?,
162            materials: read_materials(geom_node_handle, nodes)?,
163            tangents: read_tangents(geom_node_handle, nodes)?,
164            binormals: read_binormals(geom_node_handle, nodes)?,
165            deformers: Vec::new(),
166        })
167    }
168
169    pub(in crate::resource::fbx) fn get_skin_data(
170        &self,
171        scene: &FbxScene,
172    ) -> Result<Vec<VertexWeightSet>, FbxError> {
173        let mut out = vec![VertexWeightSet::default(); self.vertices.len()];
174        for &deformer_handle in self.deformers.iter() {
175            for &sub_deformer_handle in scene
176                .get(deformer_handle)
177                .as_deformer()?
178                .sub_deformers
179                .iter()
180            {
181                let sub_deformer = scene.get(sub_deformer_handle).as_sub_deformer()?;
182                for (index, weight) in sub_deformer.weights.iter() {
183                    let bone_set = out
184                        .get_mut(*index as usize)
185                        .ok_or(FbxError::IndexOutOfBounds)?;
186                    if !bone_set.push(VertexWeight {
187                        value: *weight,
188                        effector: sub_deformer.model.into(),
189                    }) {
190                        // Re-normalize weights if there are more than 4 bones per vertex.
191                        bone_set.normalize();
192                    }
193                }
194            }
195        }
196        Ok(out)
197    }
198}