Skip to main content

fyrox_impl/scene/mesh/
mod.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
21//! Contains all structures and methods to create and manage mesh scene graph nodes. See [`Mesh`] docs for more info
22//! and usage examples.
23
24use crate::{
25    core::{
26        algebra::{Matrix4, Point3, Vector3, Vector4},
27        color::Color,
28        math::aabb::AxisAlignedBoundingBox,
29        parking_lot::Mutex,
30        pool::Handle,
31        reflect::prelude::*,
32        type_traits::prelude::*,
33        variable::InheritableVariable,
34        visitor::prelude::*,
35        SafeLock,
36    },
37    graph::SceneGraph,
38    graphics::ElementRange,
39    material::{
40        Material, MaterialResource, MaterialResourceBinding, MaterialResourceExtension,
41        MaterialTextureBinding,
42    },
43    renderer::{
44        self,
45        bundle::{RenderContext, RenderDataBundleStorageTrait, SurfaceInstanceData},
46        cache::DynamicSurfaceCache,
47    },
48    resource::texture::PLACEHOLDER,
49    scene::{
50        base::{Base, BaseBuilder},
51        debug::{Line, SceneDrawingContext},
52        graph::Graph,
53        mesh::{
54            buffer::{
55                TriangleBuffer, TriangleBufferRefMut, VertexAttributeDescriptor,
56                VertexAttributeUsage, VertexBuffer, VertexBufferRefMut, VertexReadTrait,
57                VertexViewMut, VertexWriteTrait,
58            },
59            surface::SurfaceBuilder,
60            surface::{BlendShape, Surface, SurfaceData, SurfaceResource},
61        },
62        node::constructor::NodeConstructor,
63        node::{Node, NodeTrait, RdcControlFlow, SyncContext},
64    },
65};
66use fxhash::{FxHashMap, FxHasher};
67use fyrox_graph::constructor::ConstructorProvider;
68use fyrox_resource::untyped::ResourceKind;
69use std::{
70    cell::Cell,
71    hash::{Hash, Hasher},
72    ops::{Deref, DerefMut},
73};
74use strum_macros::{AsRefStr, EnumString, VariantNames};
75
76pub mod buffer;
77pub mod surface;
78pub mod vertex;
79
80/// Defines a path that should be used to render a mesh.
81#[derive(
82    Default,
83    Copy,
84    Clone,
85    PartialOrd,
86    PartialEq,
87    Eq,
88    Ord,
89    Hash,
90    Debug,
91    Visit,
92    Reflect,
93    AsRefStr,
94    EnumString,
95    VariantNames,
96    TypeUuidProvider,
97)]
98#[type_uuid(id = "009bccb6-42e4-4dc6-bb26-6a8a70b3fab9")]
99#[repr(u32)]
100pub enum RenderPath {
101    /// Deferred rendering has much better performance than Forward, but it does not support transparent
102    /// objects and there is no way to change blending. Deferred rendering is default rendering path.
103    #[default]
104    Deferred = 0,
105
106    /// Forward rendering path supports translucency and custom blending. However current support
107    /// of forward rendering is very little. It is ideal for transparent objects like glass.
108    Forward = 1,
109}
110
111fn transform_vertex(mut vertex: VertexViewMut, world: &Matrix4<f32>) {
112    if let Ok(position) = vertex.cast_attribute::<Vector3<f32>>(VertexAttributeUsage::Position) {
113        *position = world.transform_point(&(*position).into()).coords;
114    }
115    if let Ok(normal) = vertex.cast_attribute::<Vector3<f32>>(VertexAttributeUsage::Normal) {
116        *normal = world.transform_vector(normal);
117    }
118    if let Ok(tangent) = vertex.cast_attribute::<Vector4<f32>>(VertexAttributeUsage::Tangent) {
119        let new_tangent = world.transform_vector(&tangent.xyz());
120        *tangent = Vector4::new(
121            new_tangent.x,
122            new_tangent.y,
123            new_tangent.z,
124            // Keep handedness.
125            tangent.w,
126        );
127    }
128}
129
130/// Batching mode defines how the mesh data will be grouped before rendering.
131#[derive(
132    Default,
133    Copy,
134    Clone,
135    PartialOrd,
136    PartialEq,
137    Eq,
138    Ord,
139    Hash,
140    Debug,
141    Visit,
142    Reflect,
143    AsRefStr,
144    EnumString,
145    VariantNames,
146    TypeUuidProvider,
147)]
148#[type_uuid(id = "745e6f32-63f5-46fe-8edb-9708699ae328")]
149#[repr(u32)]
150pub enum BatchingMode {
151    /// No batching. The mesh will be drawn in a separate draw call.
152    #[default]
153    None,
154    /// Static batching. Render data of all **descendant** nodes will be baked into a static buffer
155    /// and it will be drawn. This mode "bakes" world transform of a node into vertices, thus making
156    /// them immovable.
157    Static,
158    /// Dynamic batching. Render data of the mesh will be merged with the same meshes dynamically on
159    /// each frame, thus allowing the meshes to be movable. This could be slow if used incorrectly!
160    Dynamic,
161}
162
163#[derive(Debug, Clone)]
164struct Batch {
165    data: SurfaceResource,
166    material: MaterialResource,
167}
168
169#[derive(Debug, Default, Clone)]
170struct BatchContainer {
171    batches: FxHashMap<u64, Batch>,
172}
173
174impl BatchContainer {
175    fn fill(&mut self, from: Handle<Node>, ctx: &mut RenderContext) {
176        for (descendant_handle, descendant) in ctx.graph.traverse_iter(from) {
177            if descendant_handle == from {
178                continue;
179            }
180
181            descendant.collect_render_data(&mut RenderContext {
182                render_mask: ctx.render_mask,
183                elapsed_time: ctx.elapsed_time,
184                observer_position: ctx.observer_position,
185                frustum: None,
186                storage: self,
187                graph: ctx.graph,
188                render_pass_name: ctx.render_pass_name,
189                dynamic_surface_cache: ctx.dynamic_surface_cache,
190            });
191        }
192    }
193}
194
195#[derive(Debug, Default)]
196struct BatchContainerWrapper(Mutex<BatchContainer>);
197
198impl Clone for BatchContainerWrapper {
199    fn clone(&self) -> Self {
200        Self(Mutex::new(self.0.safe_lock().clone()))
201    }
202}
203
204impl RenderDataBundleStorageTrait for BatchContainer {
205    fn push_triangles(
206        &mut self,
207        dynamic_surface_cache: &mut DynamicSurfaceCache,
208        layout: &[VertexAttributeDescriptor],
209        material: &MaterialResource,
210        _render_path: RenderPath,
211        _sort_index: u64,
212        _node_handle: Handle<Node>,
213        func: &mut dyn FnMut(VertexBufferRefMut, TriangleBufferRefMut),
214    ) {
215        let mut hasher = FxHasher::default();
216        layout.hash(&mut hasher);
217        hasher.write_u64(material.key());
218        let batch_hash = hasher.finish();
219
220        let batch = self.batches.entry(batch_hash).or_insert_with(|| Batch {
221            data: dynamic_surface_cache.get_or_create(batch_hash, layout),
222            material: material.clone(),
223        });
224
225        let mut batch_data_guard = batch.data.data_ref();
226        let batch_data = &mut *batch_data_guard;
227
228        func(
229            batch_data.vertex_buffer.modify(),
230            batch_data.geometry_buffer.modify(),
231        );
232    }
233
234    fn push(
235        &mut self,
236        data: &SurfaceResource,
237        material: &MaterialResource,
238        _render_path: RenderPath,
239        _sort_index: u64,
240        instance_data: SurfaceInstanceData,
241    ) {
242        let src_data = data.data_ref();
243
244        let mut hasher = FxHasher::default();
245        src_data.vertex_buffer.layout().hash(&mut hasher);
246        hasher.write_u64(material.key());
247        let batch_hash = hasher.finish();
248
249        let batch = self.batches.entry(batch_hash).or_insert_with(|| Batch {
250            data: SurfaceResource::new_ok(
251                Uuid::new_v4(),
252                ResourceKind::Embedded,
253                SurfaceData::new(
254                    src_data.vertex_buffer.clone_empty(4096),
255                    TriangleBuffer::new(Vec::with_capacity(4096)),
256                ),
257            ),
258            material: material.clone(),
259        });
260
261        let mut batch_data_guard = batch.data.data_ref();
262        let batch_data = &mut *batch_data_guard;
263        let start_vertex_index = batch_data.vertex_buffer.vertex_count();
264        let mut batch_vertex_buffer = batch_data.vertex_buffer.modify();
265        for src_vertex in src_data.vertex_buffer.iter() {
266            batch_vertex_buffer
267                .push_vertex_raw(&src_vertex.transform(&mut |vertex| {
268                    transform_vertex(vertex, &instance_data.world_transform)
269                }))
270                .expect("Vertex size must match!");
271        }
272
273        let mut batch_geometry_buffer = batch_data.geometry_buffer.modify();
274        batch_geometry_buffer.push_triangles_with_offset(
275            start_vertex_index,
276            src_data.geometry_buffer.triangles_ref(),
277        );
278    }
279}
280
281/// Mesh is a 3D model, each mesh split into multiple surfaces, each surface represents a patch of the mesh with a single material
282/// assigned to each face. See [`Surface`] docs for more info.
283///
284/// ## How to create
285///
286/// Usually there is no need to manually create meshes, it is much easier to make one in a 3d modelling software or just download
287/// some model you like and load it in engine. See [`crate::resource::model::Model`] docs for more info about model resources.
288///
289/// However, sometimes there's a need to create meshes manually (for example - in games with procedurally-generated content). You
290/// can do it like so:
291///
292/// ```rust
293/// # use fyrox_impl::{
294/// #     core::{algebra::Matrix4, pool::Handle},
295/// #     scene::{
296/// #         base::BaseBuilder,
297/// #         graph::Graph,
298/// #         mesh::{
299/// #             surface::{SurfaceBuilder, SurfaceData, SurfaceResource},
300/// #             MeshBuilder,
301/// #         },
302/// #         node::Node,
303/// #     },
304/// # };
305/// # use fyrox_impl::scene::mesh::Mesh;
306/// # use fyrox_resource::untyped::ResourceKind;
307/// fn create_cube_mesh(graph: &mut Graph) -> Handle<Mesh> {
308///     let cube_surface_data = SurfaceData::make_cube(Matrix4::identity());
309///
310///     let cube_surface = SurfaceBuilder::new(SurfaceResource::new_embedded(cube_surface_data)).build();
311///
312///     MeshBuilder::new(BaseBuilder::new())
313///         .with_surfaces(vec![cube_surface])
314///         .build(graph)
315/// }
316/// ```
317///
318/// This example creates a unit cube surface with default material and then creates a mesh with this surface. If you need to create
319/// custom surface, see [`crate::scene::mesh::surface::SurfaceData`] docs for more info.
320#[derive(Debug, Reflect, Clone, Visit, ComponentProvider)]
321#[reflect(derived_type = "Node")]
322pub struct Mesh {
323    #[visit(rename = "Common")]
324    base: Base,
325
326    #[reflect(setter = "set_surfaces")]
327    surfaces: InheritableVariable<Vec<Surface>>,
328
329    #[reflect(setter = "set_render_path")]
330    render_path: InheritableVariable<RenderPath>,
331
332    /// Defines the batching mode used by the mesh.
333    ///
334    /// ## Static batching
335    ///
336    /// Static batching. Render data of all **descendant** nodes will be baked into a static buffer,
337    /// and it will be drawn. This mode "bakes" world transform of a node into vertices, thus making
338    /// them immovable.
339    ///
340    /// ## Dynamic Batching
341    ///
342    /// Dynamically merges render data of all **descendant** nodes. It could be useful to reduce the
343    /// number of draw calls per frame if you have lots of meshes with small vertex count. Does not
344    /// work with meshes that have skin or blend shapes. Such meshes will be drawn in a separate draw
345    /// call.
346    #[visit(optional)]
347    #[reflect(setter = "set_batching_mode")]
348    batching_mode: InheritableVariable<BatchingMode>,
349
350    #[visit(optional)]
351    blend_shapes_property_name: String,
352
353    #[visit(optional)]
354    blend_shapes: InheritableVariable<Vec<BlendShape>>,
355
356    #[reflect(hidden)]
357    #[visit(skip)]
358    local_bounding_box: Cell<AxisAlignedBoundingBox>,
359
360    #[reflect(hidden)]
361    #[visit(skip)]
362    local_bounding_box_dirty: Cell<bool>,
363
364    #[reflect(hidden)]
365    #[visit(skip)]
366    world_bounding_box: Cell<AxisAlignedBoundingBox>,
367
368    #[reflect(hidden)]
369    #[visit(skip)]
370    batch_container: BatchContainerWrapper,
371}
372
373impl Default for Mesh {
374    fn default() -> Self {
375        Self {
376            base: Default::default(),
377            surfaces: Default::default(),
378            local_bounding_box: Default::default(),
379            world_bounding_box: Default::default(),
380            local_bounding_box_dirty: Cell::new(true),
381            render_path: InheritableVariable::new_modified(RenderPath::Deferred),
382            batching_mode: Default::default(),
383            blend_shapes_property_name: Mesh::DEFAULT_BLEND_SHAPES_PROPERTY_NAME.to_string(),
384            blend_shapes: Default::default(),
385            batch_container: Default::default(),
386        }
387    }
388}
389
390impl Deref for Mesh {
391    type Target = Base;
392
393    fn deref(&self) -> &Self::Target {
394        &self.base
395    }
396}
397
398impl DerefMut for Mesh {
399    fn deref_mut(&mut self) -> &mut Self::Target {
400        &mut self.base
401    }
402}
403
404impl TypeUuidProvider for Mesh {
405    fn type_uuid() -> Uuid {
406        uuid!("caaf9d7b-bd74-48ce-b7cc-57e9dc65c2e6")
407    }
408}
409
410impl Mesh {
411    /// Default name of the blend shapes storage property in a shader.
412    pub const DEFAULT_BLEND_SHAPES_PROPERTY_NAME: &'static str = "blendShapesStorage";
413
414    /// Sets surfaces for the mesh.
415    pub fn set_surfaces(&mut self, surfaces: Vec<Surface>) -> Vec<Surface> {
416        self.surfaces.set_value_and_mark_modified(surfaces)
417    }
418
419    /// Returns shared reference to array of surfaces.
420    #[inline]
421    pub fn surfaces(&self) -> &[Surface] {
422        &self.surfaces
423    }
424
425    /// Returns mutable reference to array of surfaces.
426    #[inline]
427    pub fn surfaces_mut(&mut self) -> &mut [Surface] {
428        self.local_bounding_box_dirty.set(true);
429        self.surfaces.get_value_mut_silent()
430    }
431
432    /// Removes all surfaces from mesh.
433    #[inline]
434    pub fn clear_surfaces(&mut self) {
435        self.surfaces.get_value_mut_and_mark_modified().clear();
436        self.local_bounding_box_dirty.set(true);
437    }
438
439    /// Adds new surface into mesh, can be used to procedurally generate meshes.
440    #[inline]
441    pub fn add_surface(&mut self, surface: Surface) {
442        self.surfaces
443            .get_value_mut_and_mark_modified()
444            .push(surface);
445        self.local_bounding_box_dirty.set(true);
446    }
447
448    /// Returns a list of blend shapes.
449    pub fn blend_shapes(&self) -> &[BlendShape] {
450        &self.blend_shapes
451    }
452
453    /// Returns a list of blend shapes.
454    pub fn blend_shapes_mut(&mut self) -> &mut [BlendShape] {
455        self.blend_shapes.get_value_mut_and_mark_modified()
456    }
457
458    /// Sets new render path for the mesh.
459    pub fn set_render_path(&mut self, render_path: RenderPath) -> RenderPath {
460        self.render_path.set_value_and_mark_modified(render_path)
461    }
462
463    /// Returns current render path of the mesh.
464    pub fn render_path(&self) -> RenderPath {
465        *self.render_path
466    }
467
468    /// Calculate very accurate bounding box in *world coordinates* including influence of bones.
469    /// This method is very heavy and not intended to use every frame!
470    pub fn accurate_world_bounding_box(&self, graph: &Graph) -> AxisAlignedBoundingBox {
471        let mut bounding_box = AxisAlignedBoundingBox::default();
472        for surface in self.surfaces.iter() {
473            let data = surface.data();
474            let data = data.data_ref();
475            if surface.bones().is_empty() {
476                for view in data.vertex_buffer.iter() {
477                    let Ok(vertex_pos) = view.read_3_f32(VertexAttributeUsage::Position) else {
478                        break;
479                    };
480
481                    bounding_box.add_point(
482                        self.global_transform()
483                            .transform_point(&Point3::from(vertex_pos))
484                            .coords,
485                    );
486                }
487            } else {
488                // Special case for skinned surface. Its actual bounds defined only by bones
489                // influence.
490
491                // Precalculate bone matrices first to speed up calculations.
492                let bone_matrices = surface
493                    .bones()
494                    .iter()
495                    .map(|&b| {
496                        let bone_node = &graph[b];
497                        bone_node.global_transform() * bone_node.inv_bind_pose_transform()
498                    })
499                    .collect::<Vec<Matrix4<f32>>>();
500
501                for view in data.vertex_buffer.iter() {
502                    let mut position = Vector3::default();
503
504                    let Ok(vertex_pos) = view.read_3_f32(VertexAttributeUsage::Position) else {
505                        break;
506                    };
507                    let Ok(bone_indices) = view.read_4_u8(VertexAttributeUsage::BoneIndices) else {
508                        break;
509                    };
510                    let Ok(bone_weights) = view.read_4_f32(VertexAttributeUsage::BoneWeight) else {
511                        break;
512                    };
513
514                    for (&bone_index, &weight) in bone_indices.iter().zip(bone_weights.iter()) {
515                        position += bone_matrices[bone_index as usize]
516                            .transform_point(&Point3::from(vertex_pos))
517                            .coords
518                            .scale(weight);
519                    }
520
521                    bounding_box.add_point(position);
522                }
523            }
524        }
525        bounding_box
526    }
527
528    /// Defines the batching mode used by the mesh.
529    ///
530    /// ## Static batching
531    ///
532    /// Static batching. Render data of all **descendant** nodes will be baked into a static buffer,
533    /// and it will be drawn. This mode "bakes" world transform of a node into vertices, thus making
534    /// them immovable.
535    ///
536    /// ## Dynamic Batching
537    ///
538    /// Dynamically merges render data of all **descendant** nodes. It could be useful to reduce the
539    /// number of draw calls per frame if you have lots of meshes with small vertex count. Does not
540    /// work with meshes that have skin or blend shapes. Such meshes will be drawn in a separate draw
541    /// call.
542    pub fn set_batching_mode(&mut self, mode: BatchingMode) -> BatchingMode {
543        if let BatchingMode::None | BatchingMode::Dynamic = mode {
544            // Destroy batched data.
545            std::mem::take(&mut self.batch_container);
546        }
547
548        self.batching_mode.set_value_and_mark_modified(mode)
549    }
550
551    /// Returns `true` if the dynamic batching is enabled, `false` otherwise.
552    pub fn batching_mode(&self) -> BatchingMode {
553        *self.batching_mode
554    }
555}
556
557fn extend_aabb_from_vertex_buffer(
558    vertex_buffer: &VertexBuffer,
559    bounding_box: &mut AxisAlignedBoundingBox,
560) {
561    if let Some(position_attribute_view) =
562        vertex_buffer.attribute_view::<Vector3<f32>>(VertexAttributeUsage::Position)
563    {
564        for i in 0..vertex_buffer.vertex_count() as usize {
565            bounding_box.add_point(*position_attribute_view.get(i).unwrap());
566        }
567    }
568}
569
570fn placeholder_material() -> MaterialResource {
571    let mut material = Material::standard();
572    material.bind("diffuseTexture", PLACEHOLDER.resource());
573    MaterialResource::new_ok(Uuid::new_v4(), ResourceKind::Embedded, material)
574}
575
576impl ConstructorProvider<Node, Graph> for Mesh {
577    fn constructor() -> NodeConstructor {
578        NodeConstructor::new::<Self>()
579            .with_variant("Empty", |_| {
580                MeshBuilder::new(BaseBuilder::new()).build_node().into()
581            })
582            .with_variant("Cube", |_| {
583                MeshBuilder::new(BaseBuilder::new().with_name("Cube"))
584                    .with_surfaces(vec![SurfaceBuilder::new(surface::CUBE.resource.clone())
585                        .with_material(placeholder_material())
586                        .build()])
587                    .build_node()
588                    .into()
589            })
590            .with_variant("Cone", |_| {
591                MeshBuilder::new(BaseBuilder::new().with_name("Cone"))
592                    .with_surfaces(vec![SurfaceBuilder::new(surface::CONE.resource.clone())
593                        .with_material(placeholder_material())
594                        .build()])
595                    .build_node()
596                    .into()
597            })
598            .with_variant("Cylinder", |_| {
599                MeshBuilder::new(BaseBuilder::new().with_name("Cylinder"))
600                    .with_surfaces(vec![SurfaceBuilder::new(
601                        surface::CYLINDER.resource.clone(),
602                    )
603                    .with_material(placeholder_material())
604                    .build()])
605                    .build_node()
606                    .into()
607            })
608            .with_variant("Sphere", |_| {
609                MeshBuilder::new(BaseBuilder::new().with_name("Sphere"))
610                    .with_surfaces(vec![SurfaceBuilder::new(surface::SPHERE.resource.clone())
611                        .with_material(placeholder_material())
612                        .build()])
613                    .build_node()
614                    .into()
615            })
616            .with_variant("Quad", |_| {
617                MeshBuilder::new(BaseBuilder::new().with_name("Quad"))
618                    .with_surfaces(vec![SurfaceBuilder::new(surface::QUAD.resource.clone())
619                        .with_material(placeholder_material())
620                        .build()])
621                    .build_node()
622                    .into()
623            })
624            .with_group("Mesh")
625    }
626}
627
628impl NodeTrait for Mesh {
629    /// Returns current bounding box. Bounding box presented in *local coordinates*
630    /// WARNING: This method does *not* includes bounds of bones!
631    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
632        if self.local_bounding_box_dirty.get() {
633            let mut bounding_box = AxisAlignedBoundingBox::default();
634
635            if let BatchingMode::Static = *self.batching_mode {
636                let container = self.batch_container.0.safe_lock();
637                for batch in container.batches.values() {
638                    let data = batch.data.data_ref();
639                    extend_aabb_from_vertex_buffer(&data.vertex_buffer, &mut bounding_box);
640                }
641            } else {
642                for surface in self.surfaces.iter() {
643                    let data = surface.data();
644                    if data.is_ok() {
645                        let data = data.data_ref();
646                        extend_aabb_from_vertex_buffer(&data.vertex_buffer, &mut bounding_box);
647                    }
648                }
649            }
650
651            self.local_bounding_box.set(bounding_box);
652            self.local_bounding_box_dirty.set(false);
653        }
654
655        self.local_bounding_box.get()
656    }
657
658    /// Returns current **world-space** bounding box.
659    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
660        self.world_bounding_box.get()
661    }
662
663    fn id(&self) -> Uuid {
664        Self::type_uuid()
665    }
666
667    fn on_global_transform_changed(
668        &self,
669        new_global_transform: &Matrix4<f32>,
670        context: &mut SyncContext,
671    ) {
672        if self.surfaces.iter().any(|s| !s.bones.is_empty()) {
673            let mut world_aabb = self.local_bounding_box().transform(new_global_transform);
674
675            // Special case for skinned meshes.
676            for surface in self.surfaces.iter() {
677                for &bone in surface.bones() {
678                    if let Ok(node) = context.nodes.try_borrow(bone) {
679                        world_aabb.add_point(node.global_position())
680                    }
681                }
682            }
683
684            self.world_bounding_box.set(world_aabb)
685        } else {
686            self.world_bounding_box
687                .set(self.local_bounding_box().transform(new_global_transform));
688        }
689    }
690
691    fn collect_render_data(&self, ctx: &mut RenderContext) -> RdcControlFlow {
692        if !self.should_be_rendered(ctx.frustum, ctx.render_mask) {
693            return RdcControlFlow::Continue;
694        }
695
696        if renderer::is_shadow_pass(ctx.render_pass_name) && !self.cast_shadows() {
697            return RdcControlFlow::Continue;
698        }
699
700        let sorting_index = ctx.calculate_sorting_index(self.global_position());
701
702        if let BatchingMode::Static = *self.batching_mode {
703            let mut container = self.batch_container.0.safe_lock();
704
705            if container.batches.is_empty() {
706                container.fill(self.handle(), ctx);
707            }
708
709            for batch in container.batches.values() {
710                ctx.storage.push(
711                    &batch.data,
712                    &batch.material,
713                    self.render_path(),
714                    sorting_index,
715                    SurfaceInstanceData {
716                        world_transform: Matrix4::identity(),
717                        bone_matrices: Default::default(),
718                        blend_shapes_weights: Default::default(),
719                        element_range: ElementRange::Full,
720                        node_handle: self.handle(),
721                    },
722                );
723            }
724
725            RdcControlFlow::Break
726        } else {
727            for surface in self.surfaces().iter() {
728                if !surface.data_ref().is_ok() {
729                    continue;
730                }
731                let is_skinned = !surface.bones.is_empty();
732
733                let world = if is_skinned {
734                    Matrix4::identity()
735                } else {
736                    self.global_transform()
737                };
738
739                let batching_mode = match *self.batching_mode {
740                    BatchingMode::None => BatchingMode::None,
741                    BatchingMode::Static => BatchingMode::Static,
742                    BatchingMode::Dynamic => {
743                        let surface_data_guard = surface.data_ref().data_ref();
744                        if self.blend_shapes().is_empty()
745                            && surface.bones().is_empty()
746                            && surface_data_guard.vertex_buffer.vertex_count() < 256
747                        {
748                            BatchingMode::Dynamic
749                        } else {
750                            BatchingMode::None
751                        }
752                    }
753                };
754
755                match batching_mode {
756                    BatchingMode::None => {
757                        let surface_data = surface.data_ref();
758                        let substitute_material = surface_data
759                            .data_ref()
760                            .blend_shapes_container
761                            .as_ref()
762                            .and_then(|c| c.blend_shape_storage.as_ref())
763                            .map(|texture| {
764                                let material_copy = surface.material().deep_copy();
765                                material_copy.data_ref().bind(
766                                    &self.blend_shapes_property_name,
767                                    MaterialResourceBinding::Texture(MaterialTextureBinding {
768                                        value: Some(texture.clone()),
769                                    }),
770                                );
771                                material_copy
772                            });
773
774                        ctx.storage.push(
775                            surface_data,
776                            substitute_material.as_ref().unwrap_or(surface.material()),
777                            self.render_path(),
778                            sorting_index,
779                            SurfaceInstanceData {
780                                world_transform: world,
781                                bone_matrices: surface
782                                    .bones
783                                    .iter()
784                                    .map(|bone_handle| {
785                                        if let Ok(bone_node) = ctx.graph.try_get_node(*bone_handle)
786                                        {
787                                            bone_node.global_transform()
788                                                * bone_node.inv_bind_pose_transform()
789                                        } else {
790                                            Matrix4::identity()
791                                        }
792                                    })
793                                    .collect::<Vec<_>>(),
794                                blend_shapes_weights: self
795                                    .blend_shapes()
796                                    .iter()
797                                    .map(|bs| bs.weight / 100.0)
798                                    .collect(),
799                                element_range: ElementRange::Full,
800                                node_handle: self.handle(),
801                            },
802                        );
803                    }
804                    BatchingMode::Dynamic => {
805                        let surface_data_guard = surface.data_ref().data_ref();
806
807                        ctx.storage.push_triangles(
808                            ctx.dynamic_surface_cache,
809                            &surface_data_guard
810                                .vertex_buffer
811                                .layout_descriptor()
812                                .collect::<Vec<_>>(),
813                            surface.material(),
814                            *self.render_path,
815                            sorting_index,
816                            self.handle(),
817                            &mut move |mut vertex_buffer, mut triangle_buffer| {
818                                let start_vertex_index = vertex_buffer.vertex_count();
819
820                                for vertex in surface_data_guard.vertex_buffer.iter() {
821                                    vertex_buffer
822                                        .push_vertex_raw(&vertex.transform(&mut |vertex| {
823                                            transform_vertex(vertex, &world)
824                                        }))
825                                        .unwrap();
826                                }
827
828                                triangle_buffer.push_triangles_with_offset(
829                                    start_vertex_index,
830                                    surface_data_guard.geometry_buffer.triangles_ref(),
831                                )
832                            },
833                        );
834                    }
835                    _ => (),
836                }
837            }
838
839            RdcControlFlow::Continue
840        }
841    }
842
843    fn debug_draw(&self, ctx: &mut SceneDrawingContext) {
844        let transform = self.global_transform();
845
846        for surface in self.surfaces() {
847            for vertex in surface.data().data_ref().vertex_buffer.iter() {
848                let len = 0.025;
849                let position = transform
850                    .transform_point(&Point3::from(
851                        vertex.read_3_f32(VertexAttributeUsage::Position).unwrap(),
852                    ))
853                    .coords;
854                let vertex_tangent = vertex.read_4_f32(VertexAttributeUsage::Tangent).unwrap();
855                let tangent = transform
856                    .transform_vector(&vertex_tangent.xyz())
857                    .normalize()
858                    .scale(len);
859                let normal = transform
860                    .transform_vector(
861                        &vertex
862                            .read_3_f32(VertexAttributeUsage::Normal)
863                            .unwrap()
864                            .xyz(),
865                    )
866                    .normalize()
867                    .scale(len);
868                let binormal = normal
869                    .xyz()
870                    .cross(&tangent)
871                    .scale(vertex_tangent.w)
872                    .normalize()
873                    .scale(len);
874
875                ctx.add_line(Line {
876                    begin: position,
877                    end: position + tangent,
878                    color: Color::RED,
879                });
880
881                ctx.add_line(Line {
882                    begin: position,
883                    end: position + normal,
884                    color: Color::BLUE,
885                });
886
887                ctx.add_line(Line {
888                    begin: position,
889                    end: position + binormal,
890                    color: Color::GREEN,
891                });
892            }
893        }
894    }
895}
896
897/// Mesh builder allows you to construct mesh in declarative manner.
898pub struct MeshBuilder {
899    base_builder: BaseBuilder,
900    surfaces: Vec<Surface>,
901    render_path: RenderPath,
902    blend_shapes: Vec<BlendShape>,
903    batching_mode: BatchingMode,
904    blend_shapes_property_name: String,
905}
906
907impl MeshBuilder {
908    /// Creates new instance of mesh builder.
909    pub fn new(base_builder: BaseBuilder) -> Self {
910        Self {
911            base_builder,
912            surfaces: Default::default(),
913            render_path: RenderPath::Deferred,
914            blend_shapes: Default::default(),
915            batching_mode: BatchingMode::None,
916            blend_shapes_property_name: Mesh::DEFAULT_BLEND_SHAPES_PROPERTY_NAME.to_string(),
917        }
918    }
919
920    /// Sets desired surfaces for mesh.
921    pub fn with_surfaces(mut self, surfaces: Vec<Surface>) -> Self {
922        self.surfaces = surfaces;
923        self
924    }
925
926    /// Sets desired render path. Keep in mind that RenderPath::Forward is not fully
927    /// implemented and only used to render transparent objects!
928    pub fn with_render_path(mut self, render_path: RenderPath) -> Self {
929        self.render_path = render_path;
930        self
931    }
932
933    /// Sets the list of blend shapes. Keep in mind that actual blend shape data must be baked in surface data
934    /// of every surface used by the mesh. Blend shapes are shared across all surfaces.
935    pub fn with_blend_shapes(mut self, blend_shapes: Vec<BlendShape>) -> Self {
936        self.blend_shapes = blend_shapes;
937        self
938    }
939
940    /// Sets the desired batching mode. See [`BatchingMode`] docs for more info.
941    pub fn with_batching_mode(mut self, mode: BatchingMode) -> Self {
942        self.batching_mode = mode;
943        self
944    }
945
946    /// Sets a name of the blend shapes property in a material used by this mesh.
947    pub fn with_blend_shapes_property_name(mut self, name: String) -> Self {
948        self.blend_shapes_property_name = name;
949        self
950    }
951
952    /// Creates new mesh.
953    pub fn build_node(self) -> Node {
954        Node::new(Mesh {
955            blend_shapes: self.blend_shapes.into(),
956            base: self.base_builder.build_base(),
957            surfaces: self.surfaces.into(),
958            local_bounding_box: Default::default(),
959            local_bounding_box_dirty: Cell::new(true),
960            render_path: self.render_path.into(),
961            world_bounding_box: Default::default(),
962            batching_mode: self.batching_mode.into(),
963            batch_container: Default::default(),
964            blend_shapes_property_name: self.blend_shapes_property_name,
965        })
966    }
967
968    /// Creates new mesh and adds it to the graph.
969    pub fn build(self, graph: &mut Graph) -> Handle<Mesh> {
970        graph.add_node(self.build_node()).to_variant()
971    }
972}