three_d/renderer/geometry/
instanced_mesh.rs1use crate::core::*;
2use crate::renderer::*;
3use std::sync::RwLock;
4
5use super::BaseMesh;
6
7pub struct InstancedMesh {
11 context: Context,
12 base_mesh: BaseMesh,
13 transform: RwLock<(
14 InstanceBuffer<Vec4>,
15 InstanceBuffer<Vec4>,
16 InstanceBuffer<Vec4>,
17 )>,
18 indices: RwLock<Vec<usize>>,
19 tex_transform: RwLock<Option<(InstanceBuffer<Vec3>, InstanceBuffer<Vec3>)>>,
20 instance_color: RwLock<Option<InstanceBuffer<Vec4>>>,
21 last_camera_position: RwLock<Option<Vec3>>,
22 aabb: AxisAlignedBoundingBox, instance_aabb: AxisAlignedBoundingBox, transformation: Mat4,
25 animation_transformation: Mat4,
26 animation: Option<Box<dyn Fn(f32) -> Mat4 + Send + Sync>>,
27 instances: Instances,
28}
29
30impl InstancedMesh {
31 pub fn new(context: &Context, instances: &Instances, cpu_mesh: &CpuMesh) -> Self {
37 #[cfg(debug_assertions)]
38 instances.validate().expect("invalid instances");
39
40 let aabb = cpu_mesh.compute_aabb();
41 let mut instanced_mesh = Self {
42 context: context.clone(),
43 base_mesh: BaseMesh::new(context, cpu_mesh),
44 transform: RwLock::new((
45 InstanceBuffer::<Vec4>::new(context),
46 InstanceBuffer::<Vec4>::new(context),
47 InstanceBuffer::<Vec4>::new(context),
48 )),
49 tex_transform: RwLock::new(None),
50 instance_color: RwLock::new(None),
51 last_camera_position: RwLock::new(None),
52 indices: RwLock::new((0..instances.transformations.len()).collect::<Vec<usize>>()),
53 aabb,
54 instance_aabb: AxisAlignedBoundingBox::INFINITE,
55 transformation: Mat4::identity(),
56 animation_transformation: Mat4::identity(),
57 animation: None,
58 instances: instances.clone(),
59 };
60 instanced_mesh.update_instance_aabb();
61 instanced_mesh.update_instance_buffers();
62 instanced_mesh
63 }
64
65 pub fn transformation(&self) -> Mat4 {
69 self.transformation
70 }
71
72 pub fn set_transformation(&mut self, transformation: Mat4) {
77 self.transformation = transformation;
78 *self.last_camera_position.write().unwrap() = None;
79 }
80
81 pub fn set_animation(&mut self, animation: impl Fn(f32) -> Mat4 + Send + Sync + 'static) {
87 self.animation = Some(Box::new(animation));
88 self.animate(0.0);
89 }
90
91 pub fn instance_count(&self) -> u32 {
93 self.instances.count()
94 }
95
96 pub fn set_instances(&mut self, instances: &Instances) {
100 #[cfg(debug_assertions)]
101 instances.validate().expect("invalid instances");
102 self.instances = instances.clone();
103 *self.indices.write().unwrap() =
104 (0..instances.transformations.len()).collect::<Vec<usize>>();
105 *self.last_camera_position.write().unwrap() = None;
106 self.update_instance_aabb();
107 self.update_instance_buffers();
108 }
109
110 fn update_instance_aabb(&mut self) {
111 let mut aabb = AxisAlignedBoundingBox::EMPTY;
112 for instance_transformation in &self.instances.transformations {
113 aabb.expand_with_aabb(
114 self.aabb
115 .transformed(instance_transformation * self.animation_transformation),
116 );
117 }
118 self.instance_aabb = aabb;
119 }
120
121 fn update_instance_buffers(&self) {
125 let indices = self.indices.read().unwrap();
126 let mut row1 = Vec::new();
127 let mut row2 = Vec::new();
128 let mut row3 = Vec::new();
129 for transformation in indices.iter().map(|i| self.instances.transformations[*i]) {
130 row1.push(transformation.row(0));
131 row2.push(transformation.row(1));
132 row3.push(transformation.row(2));
133 }
134
135 *self.transform.write().unwrap() = (
136 InstanceBuffer::new_with_data(&self.context, &row1),
137 InstanceBuffer::new_with_data(&self.context, &row2),
138 InstanceBuffer::new_with_data(&self.context, &row3),
139 );
140
141 *self.tex_transform.write().unwrap() =
142 self.instances
143 .texture_transformations
144 .as_ref()
145 .map(|texture_transforms| {
146 let mut instance_tex_transform1 = Vec::new();
147 let mut instance_tex_transform2 = Vec::new();
148 for texture_transform in indices.iter().map(|i| texture_transforms[*i]) {
149 instance_tex_transform1.push(vec3(
150 texture_transform.x.x,
151 texture_transform.y.x,
152 texture_transform.z.x,
153 ));
154 instance_tex_transform2.push(vec3(
155 texture_transform.x.y,
156 texture_transform.y.y,
157 texture_transform.z.y,
158 ));
159 }
160 (
161 InstanceBuffer::new_with_data(&self.context, &instance_tex_transform1),
162 InstanceBuffer::new_with_data(&self.context, &instance_tex_transform2),
163 )
164 });
165 *self.instance_color.write().unwrap() =
166 self.instances.colors.as_ref().map(|instance_colors| {
167 let ordered_instance_colors = indices
168 .iter()
169 .map(|i| instance_colors[*i].to_linear_srgb())
170 .collect::<Vec<_>>();
171 InstanceBuffer::new_with_data(&self.context, &ordered_instance_colors)
172 });
173 }
174}
175
176impl<'a> IntoIterator for &'a InstancedMesh {
177 type Item = &'a dyn Geometry;
178 type IntoIter = std::iter::Once<&'a dyn Geometry>;
179
180 fn into_iter(self) -> Self::IntoIter {
181 std::iter::once(self)
182 }
183}
184
185impl Geometry for InstancedMesh {
186 fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
187 if render_states.blend != Blend::Disabled
189 && self
190 .last_camera_position
191 .read()
192 .unwrap()
193 .map(|p| p.distance2(viewer.position()) > 0.001)
194 .unwrap_or(true)
195 {
196 *self.last_camera_position.write().unwrap() = Some(viewer.position());
197 let distances = self
198 .instances
199 .transformations
200 .iter()
201 .map(|m| {
202 (self.transformation * m * self.animation_transformation)
203 .w
204 .truncate()
205 .distance2(viewer.position())
206 })
207 .collect::<Vec<_>>();
208 self.indices.write().unwrap().sort_by(|a, b| {
209 distances[*b]
210 .partial_cmp(&distances[*a])
211 .unwrap_or(std::cmp::Ordering::Equal)
212 });
213 self.update_instance_buffers();
214 }
215
216 program.use_uniform("viewProjection", viewer.projection() * viewer.view());
217 program.use_uniform("animationTransform", self.animation_transformation);
218 program.use_uniform("modelMatrix", self.transformation);
219
220 let (row1, row2, row3) = &*self.transform.read().unwrap();
221 program.use_instance_attribute("row1", row1);
222 program.use_instance_attribute("row2", row2);
223 program.use_instance_attribute("row3", row3);
224
225 if program.requires_attribute("tex_transform_row1") {
226 if let Some((row1, row2)) = &*self.tex_transform.read().unwrap() {
227 program.use_instance_attribute("tex_transform_row1", row1);
228 program.use_instance_attribute("tex_transform_row2", row2);
229 }
230 }
231
232 if program.requires_attribute("instance_color") {
233 if let Some(color) = &*self.instance_color.read().unwrap() {
234 program.use_instance_attribute("instance_color", color);
235 }
236 }
237
238 self.base_mesh
239 .draw_instanced(program, render_states, viewer, self.instance_count());
240 }
241
242 fn vertex_shader_source(&self) -> String {
243 format!(
244 "#define USE_INSTANCE_TRANSFORMS\n{}{}{}",
245 if self.instance_color.read().unwrap().is_some() {
246 "#define USE_INSTANCE_COLORS\n"
247 } else {
248 ""
249 },
250 if self.tex_transform.read().unwrap().is_some() {
251 "#define USE_INSTANCE_TEXTURE_TRANSFORMATION\n"
252 } else {
253 ""
254 },
255 self.base_mesh.vertex_shader_source()
256 )
257 }
258
259 fn id(&self) -> GeometryId {
260 GeometryId::InstancedMesh(
261 self.base_mesh.normals.is_some(),
262 self.base_mesh.tangents.is_some(),
263 self.base_mesh.uvs.is_some(),
264 self.base_mesh.colors.is_some(),
265 self.instance_color.read().unwrap().is_some(),
266 self.tex_transform.read().unwrap().is_some(),
267 )
268 }
269
270 fn aabb(&self) -> AxisAlignedBoundingBox {
271 self.instance_aabb.transformed(self.transformation)
272 }
273
274 fn animate(&mut self, time: f32) {
275 if let Some(animation) = &self.animation {
276 self.animation_transformation = animation(time);
277 *self.last_camera_position.write().unwrap() = None;
278 self.update_instance_aabb();
279 }
280 }
281
282 fn render_with_material(
283 &self,
284 material: &dyn Material,
285 viewer: &dyn Viewer,
286 lights: &[&dyn Light],
287 ) {
288 if let Err(e) = render_with_material(&self.context, viewer, self, material, lights) {
289 panic!("{}", e.to_string());
290 }
291 }
292
293 fn render_with_effect(
294 &self,
295 material: &dyn Effect,
296 viewer: &dyn Viewer,
297 lights: &[&dyn Light],
298 color_texture: Option<ColorTexture>,
299 depth_texture: Option<DepthTexture>,
300 ) {
301 if let Err(e) = render_with_effect(
302 &self.context,
303 viewer,
304 self,
305 material,
306 lights,
307 color_texture,
308 depth_texture,
309 ) {
310 panic!("{}", e.to_string());
311 }
312 }
313}
314
315#[derive(Clone, Debug, Default)]
323pub struct Instances {
324 pub transformations: Vec<Mat4>,
327 pub texture_transformations: Option<Vec<Mat3>>,
329 pub colors: Option<Vec<Srgba>>,
331}
332
333impl Instances {
334 pub fn validate(&self) -> Result<(), RendererError> {
338 let instance_count = self.count();
339 let buffer_check = |length: Option<usize>, name: &str| -> Result<(), RendererError> {
340 if let Some(length) = length {
341 if length < instance_count as usize {
342 Err(RendererError::InvalidBufferLength(
343 name.to_string(),
344 instance_count as usize,
345 length,
346 ))?;
347 }
348 }
349 Ok(())
350 };
351
352 buffer_check(
353 self.texture_transformations.as_ref().map(|b| b.len()),
354 "texture transformations",
355 )?;
356 buffer_check(Some(self.transformations.len()), "transformations")?;
357 buffer_check(self.colors.as_ref().map(|b| b.len()), "colors")?;
358
359 Ok(())
360 }
361
362 pub fn count(&self) -> u32 {
364 self.transformations.len() as u32
365 }
366}
367
368impl From<PointCloud> for Instances {
369 fn from(points: PointCloud) -> Self {
370 Self {
371 transformations: points
372 .positions
373 .to_f32()
374 .into_iter()
375 .map(Mat4::from_translation)
376 .collect(),
377 colors: points.colors,
378 ..Default::default()
379 }
380 }
381}