three_d/renderer/geometry/
mesh.rs

1use crate::core::*;
2use crate::renderer::*;
3
4use super::BaseMesh;
5
6///
7/// A triangle mesh [Geometry].
8///
9pub struct Mesh {
10    base_mesh: BaseMesh,
11    context: Context,
12    aabb: AxisAlignedBoundingBox,
13    transformation: Mat4,
14    current_transformation: Mat4,
15    animation: Option<Box<dyn Fn(f32) -> Mat4 + Send + Sync>>,
16}
17
18impl Mesh {
19    ///
20    /// Creates a new triangle mesh from the given [CpuMesh].
21    /// All data in the [CpuMesh] is transfered to the GPU, so make sure to remove all unnecessary data from the [CpuMesh] before calling this method.
22    ///
23    pub fn new(context: &Context, cpu_mesh: &CpuMesh) -> Self {
24        let aabb = cpu_mesh.compute_aabb();
25        Self {
26            context: context.clone(),
27            base_mesh: BaseMesh::new(context, cpu_mesh),
28            aabb,
29            transformation: Mat4::identity(),
30            current_transformation: Mat4::identity(),
31            animation: None,
32        }
33    }
34
35    pub(in crate::renderer) fn set_transformation_2d(&mut self, transformation: Mat3) {
36        self.set_transformation(Mat4::new(
37            transformation.x.x,
38            transformation.x.y,
39            0.0,
40            transformation.x.z,
41            transformation.y.x,
42            transformation.y.y,
43            0.0,
44            transformation.y.z,
45            0.0,
46            0.0,
47            1.0,
48            0.0,
49            transformation.z.x,
50            transformation.z.y,
51            0.0,
52            transformation.z.z,
53        ));
54    }
55
56    ///
57    /// Returns the local to world transformation applied to this mesh.
58    ///
59    pub fn transformation(&self) -> Mat4 {
60        self.transformation
61    }
62
63    ///
64    /// Set the local to world transformation applied to this mesh.
65    /// If any animation method is set using [Self::set_animation], the transformation from that method is applied before this transformation.
66    ///
67    pub fn set_transformation(&mut self, transformation: Mat4) {
68        self.transformation = transformation;
69        self.current_transformation = transformation;
70    }
71
72    ///
73    /// Specifies a function which takes a time parameter as input and returns a transformation that should be applied to this mesh at the given time.
74    /// To actually animate this mesh, call [Geometry::animate] at each frame which in turn evaluates the animation function defined by this method.
75    /// This transformation is applied first, then the local to world transformation defined by [Self::set_transformation].
76    ///
77    pub fn set_animation(&mut self, animation: impl Fn(f32) -> Mat4 + Send + Sync + 'static) {
78        self.animation = Some(Box::new(animation));
79    }
80
81    ///
82    /// Returns the number of vertices in this mesh.
83    ///
84    pub fn vertex_count(&self) -> u32 {
85        self.base_mesh.positions.vertex_count()
86    }
87
88    ///
89    /// Used for editing the triangle indices.
90    /// Note: Changing this will possibly ruin the mesh.
91    ///
92    pub fn indices_mut(&mut self) -> &mut IndexBuffer {
93        &mut self.base_mesh.indices
94    }
95
96    ///
97    /// Used for editing the vertex positions.
98    /// Note: Changing this will possibly ruin the mesh.
99    ///
100    pub fn positions_mut(&mut self) -> &mut VertexBuffer<Vec3> {
101        &mut self.base_mesh.positions
102    }
103
104    ///
105    /// Used for editing the vertex normals.
106    /// Note: Changing this will possibly ruin the mesh.
107    ///
108    pub fn normals_mut(&mut self) -> &mut Option<VertexBuffer<Vec3>> {
109        &mut self.base_mesh.normals
110    }
111
112    ///
113    /// Used for editing the vertex uvs.
114    /// Note: Changing this will possibly ruin the mesh.
115    ///
116    pub fn uvs_mut(&mut self) -> &mut Option<VertexBuffer<Vec2>> {
117        &mut self.base_mesh.uvs
118    }
119
120    ///
121    /// Used for editing the vertex tangents.
122    /// Note: Changing this will possibly ruin the mesh.
123    ///
124    pub fn tangents_mut(&mut self) -> &mut Option<VertexBuffer<Vec4>> {
125        &mut self.base_mesh.tangents
126    }
127
128    ///
129    /// Used for editing the vertex colors.
130    /// Note: Changing this will possibly ruin the mesh.
131    ///
132    pub fn colors_mut(&mut self) -> &mut Option<VertexBuffer<Vec4>> {
133        &mut self.base_mesh.colors
134    }
135
136    /// Updates the vertex positions of the mesh.
137    ///
138    /// # Panics
139    ///
140    /// Panics if the number of positions does not match the number of vertices in the mesh.
141    #[deprecated = "use positions_mut instead"]
142    pub fn update_positions(&mut self, positions: &[Vector3<f32>]) {
143        if positions.len() as u32 != self.vertex_count() {
144            panic!("Failed updating positions: The number of positions {} does not match the number of vertices {} in the mesh.", positions.len(), self.vertex_count())
145        }
146        self.positions_mut().fill(positions);
147    }
148
149    ///
150    /// Updates the vertex normals of the mesh.
151    ///
152    /// # Panics
153    ///
154    /// Panics if the number of normals does not match the number of vertices in the mesh.
155    #[deprecated = "use normals_mut instead"]
156    pub fn update_normals(&mut self, normals: &[Vector3<f32>]) {
157        if normals.len() as u32 != self.vertex_count() {
158            panic!("Failed updating normals: The number of normals {} does not match the number of vertices {} in the mesh.", normals.len(), self.vertex_count())
159        }
160
161        if let Some(normal_buffer) = self.normals_mut() {
162            normal_buffer.fill(normals);
163        } else {
164            *self.normals_mut() = Some(VertexBuffer::new_with_data(&self.context, normals));
165        }
166    }
167}
168
169impl<'a> IntoIterator for &'a Mesh {
170    type Item = &'a dyn Geometry;
171    type IntoIter = std::iter::Once<&'a dyn Geometry>;
172
173    fn into_iter(self) -> Self::IntoIter {
174        std::iter::once(self)
175    }
176}
177
178impl Geometry for Mesh {
179    fn aabb(&self) -> AxisAlignedBoundingBox {
180        self.aabb.transformed(self.current_transformation)
181    }
182
183    fn animate(&mut self, time: f32) {
184        if let Some(animation) = &self.animation {
185            self.current_transformation = self.transformation * animation(time);
186        }
187    }
188
189    fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
190        if let Some(inverse) = self.current_transformation.invert() {
191            program.use_uniform_if_required("normalMatrix", inverse.transpose());
192        } else {
193            // determinant is float zero
194            return;
195        }
196
197        program.use_uniform("viewProjection", viewer.projection() * viewer.view());
198        program.use_uniform("modelMatrix", self.current_transformation);
199
200        self.base_mesh.draw(program, render_states, viewer);
201    }
202
203    fn vertex_shader_source(&self) -> String {
204        self.base_mesh.vertex_shader_source()
205    }
206
207    fn id(&self) -> GeometryId {
208        GeometryId::Mesh(
209            self.base_mesh.normals.is_some(),
210            self.base_mesh.tangents.is_some(),
211            self.base_mesh.uvs.is_some(),
212            self.base_mesh.colors.is_some(),
213        )
214    }
215
216    fn render_with_material(
217        &self,
218        material: &dyn Material,
219        viewer: &dyn Viewer,
220        lights: &[&dyn Light],
221    ) {
222        render_with_material(&self.context, viewer, &self, material, lights);
223    }
224
225    fn render_with_effect(
226        &self,
227        material: &dyn Effect,
228        viewer: &dyn Viewer,
229        lights: &[&dyn Light],
230        color_texture: Option<ColorTexture>,
231        depth_texture: Option<DepthTexture>,
232    ) {
233        render_with_effect(
234            &self.context,
235            viewer,
236            self,
237            material,
238            lights,
239            color_texture,
240            depth_texture,
241        )
242    }
243}