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::{BaseSceneGraph, 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_resource::untyped::ResourceKind;
306/// fn create_cube_mesh(graph: &mut Graph) -> Handle<Node> {
307///     let cube_surface_data = SurfaceData::make_cube(Matrix4::identity());
308///
309///     let cube_surface = SurfaceBuilder::new(SurfaceResource::new_embedded(cube_surface_data)).build();
310///
311///     MeshBuilder::new(BaseBuilder::new())
312///         .with_surfaces(vec![cube_surface])
313///         .build(graph)
314/// }
315/// ```
316///
317/// This example creates a unit cube surface with default material and then creates a mesh with this surface. If you need to create
318/// custom surface, see [`crate::scene::mesh::surface::SurfaceData`] docs for more info.
319#[derive(Debug, Reflect, Clone, Visit, ComponentProvider)]
320#[reflect(derived_type = "Node")]
321pub struct Mesh {
322    #[visit(rename = "Common")]
323    base: Base,
324
325    #[reflect(setter = "set_surfaces")]
326    surfaces: InheritableVariable<Vec<Surface>>,
327
328    #[reflect(setter = "set_render_path")]
329    render_path: InheritableVariable<RenderPath>,
330
331    /// Defines the batching mode used by the mesh.
332    ///
333    /// ## Static batching
334    ///
335    /// Static batching. Render data of all **descendant** nodes will be baked into a static buffer,
336    /// and it will be drawn. This mode "bakes" world transform of a node into vertices, thus making
337    /// them immovable.
338    ///
339    /// ## Dynamic Batching
340    ///
341    /// Dynamically merges render data of all **descendant** nodes. It could be useful to reduce the
342    /// number of draw calls per frame if you have lots of meshes with small vertex count. Does not
343    /// work with meshes that have skin or blend shapes. Such meshes will be drawn in a separate draw
344    /// call.
345    #[visit(optional)]
346    #[reflect(setter = "set_batching_mode")]
347    batching_mode: InheritableVariable<BatchingMode>,
348
349    #[visit(optional)]
350    blend_shapes_property_name: String,
351
352    #[visit(optional)]
353    blend_shapes: InheritableVariable<Vec<BlendShape>>,
354
355    #[reflect(hidden)]
356    #[visit(skip)]
357    local_bounding_box: Cell<AxisAlignedBoundingBox>,
358
359    #[reflect(hidden)]
360    #[visit(skip)]
361    local_bounding_box_dirty: Cell<bool>,
362
363    #[reflect(hidden)]
364    #[visit(skip)]
365    world_bounding_box: Cell<AxisAlignedBoundingBox>,
366
367    #[reflect(hidden)]
368    #[visit(skip)]
369    batch_container: BatchContainerWrapper,
370}
371
372impl Default for Mesh {
373    fn default() -> Self {
374        Self {
375            base: Default::default(),
376            surfaces: Default::default(),
377            local_bounding_box: Default::default(),
378            world_bounding_box: Default::default(),
379            local_bounding_box_dirty: Cell::new(true),
380            render_path: InheritableVariable::new_modified(RenderPath::Deferred),
381            batching_mode: Default::default(),
382            blend_shapes_property_name: Mesh::DEFAULT_BLEND_SHAPES_PROPERTY_NAME.to_string(),
383            blend_shapes: Default::default(),
384            batch_container: Default::default(),
385        }
386    }
387}
388
389impl Deref for Mesh {
390    type Target = Base;
391
392    fn deref(&self) -> &Self::Target {
393        &self.base
394    }
395}
396
397impl DerefMut for Mesh {
398    fn deref_mut(&mut self) -> &mut Self::Target {
399        &mut self.base
400    }
401}
402
403impl TypeUuidProvider for Mesh {
404    fn type_uuid() -> Uuid {
405        uuid!("caaf9d7b-bd74-48ce-b7cc-57e9dc65c2e6")
406    }
407}
408
409impl Mesh {
410    /// Default name of the blend shapes storage property in a shader.
411    pub const DEFAULT_BLEND_SHAPES_PROPERTY_NAME: &'static str = "blendShapesStorage";
412
413    /// Sets surfaces for the mesh.
414    pub fn set_surfaces(&mut self, surfaces: Vec<Surface>) -> Vec<Surface> {
415        self.surfaces.set_value_and_mark_modified(surfaces)
416    }
417
418    /// Returns shared reference to array of surfaces.
419    #[inline]
420    pub fn surfaces(&self) -> &[Surface] {
421        &self.surfaces
422    }
423
424    /// Returns mutable reference to array of surfaces.
425    #[inline]
426    pub fn surfaces_mut(&mut self) -> &mut [Surface] {
427        self.local_bounding_box_dirty.set(true);
428        self.surfaces.get_value_mut_silent()
429    }
430
431    /// Removes all surfaces from mesh.
432    #[inline]
433    pub fn clear_surfaces(&mut self) {
434        self.surfaces.get_value_mut_and_mark_modified().clear();
435        self.local_bounding_box_dirty.set(true);
436    }
437
438    /// Adds new surface into mesh, can be used to procedurally generate meshes.
439    #[inline]
440    pub fn add_surface(&mut self, surface: Surface) {
441        self.surfaces
442            .get_value_mut_and_mark_modified()
443            .push(surface);
444        self.local_bounding_box_dirty.set(true);
445    }
446
447    /// Returns a list of blend shapes.
448    pub fn blend_shapes(&self) -> &[BlendShape] {
449        &self.blend_shapes
450    }
451
452    /// Returns a list of blend shapes.
453    pub fn blend_shapes_mut(&mut self) -> &mut [BlendShape] {
454        self.blend_shapes.get_value_mut_and_mark_modified()
455    }
456
457    /// Sets new render path for the mesh.
458    pub fn set_render_path(&mut self, render_path: RenderPath) -> RenderPath {
459        self.render_path.set_value_and_mark_modified(render_path)
460    }
461
462    /// Returns current render path of the mesh.
463    pub fn render_path(&self) -> RenderPath {
464        *self.render_path
465    }
466
467    /// Calculate very accurate bounding box in *world coordinates* including influence of bones.
468    /// This method is very heavy and not intended to use every frame!
469    pub fn accurate_world_bounding_box(&self, graph: &Graph) -> AxisAlignedBoundingBox {
470        let mut bounding_box = AxisAlignedBoundingBox::default();
471        for surface in self.surfaces.iter() {
472            let data = surface.data();
473            let data = data.data_ref();
474            if surface.bones().is_empty() {
475                for view in data.vertex_buffer.iter() {
476                    let Ok(vertex_pos) = view.read_3_f32(VertexAttributeUsage::Position) else {
477                        break;
478                    };
479
480                    bounding_box.add_point(
481                        self.global_transform()
482                            .transform_point(&Point3::from(vertex_pos))
483                            .coords,
484                    );
485                }
486            } else {
487                // Special case for skinned surface. Its actual bounds defined only by bones
488                // influence.
489
490                // Precalculate bone matrices first to speed up calculations.
491                let bone_matrices = surface
492                    .bones()
493                    .iter()
494                    .map(|&b| {
495                        let bone_node = &graph[b];
496                        bone_node.global_transform() * bone_node.inv_bind_pose_transform()
497                    })
498                    .collect::<Vec<Matrix4<f32>>>();
499
500                for view in data.vertex_buffer.iter() {
501                    let mut position = Vector3::default();
502
503                    let Ok(vertex_pos) = view.read_3_f32(VertexAttributeUsage::Position) else {
504                        break;
505                    };
506                    let Ok(bone_indices) = view.read_4_u8(VertexAttributeUsage::BoneIndices) else {
507                        break;
508                    };
509                    let Ok(bone_weights) = view.read_4_f32(VertexAttributeUsage::BoneWeight) else {
510                        break;
511                    };
512
513                    for (&bone_index, &weight) in bone_indices.iter().zip(bone_weights.iter()) {
514                        position += bone_matrices[bone_index as usize]
515                            .transform_point(&Point3::from(vertex_pos))
516                            .coords
517                            .scale(weight);
518                    }
519
520                    bounding_box.add_point(position);
521                }
522            }
523        }
524        bounding_box
525    }
526
527    /// Defines the batching mode used by the mesh.
528    ///
529    /// ## Static batching
530    ///
531    /// Static batching. Render data of all **descendant** nodes will be baked into a static buffer,
532    /// and it will be drawn. This mode "bakes" world transform of a node into vertices, thus making
533    /// them immovable.
534    ///
535    /// ## Dynamic Batching
536    ///
537    /// Dynamically merges render data of all **descendant** nodes. It could be useful to reduce the
538    /// number of draw calls per frame if you have lots of meshes with small vertex count. Does not
539    /// work with meshes that have skin or blend shapes. Such meshes will be drawn in a separate draw
540    /// call.
541    pub fn set_batching_mode(&mut self, mode: BatchingMode) -> BatchingMode {
542        if let BatchingMode::None | BatchingMode::Dynamic = mode {
543            // Destroy batched data.
544            std::mem::take(&mut self.batch_container);
545        }
546
547        self.batching_mode.set_value_and_mark_modified(mode)
548    }
549
550    /// Returns `true` if the dynamic batching is enabled, `false` otherwise.
551    pub fn batching_mode(&self) -> BatchingMode {
552        *self.batching_mode
553    }
554}
555
556fn extend_aabb_from_vertex_buffer(
557    vertex_buffer: &VertexBuffer,
558    bounding_box: &mut AxisAlignedBoundingBox,
559) {
560    if let Some(position_attribute_view) =
561        vertex_buffer.attribute_view::<Vector3<f32>>(VertexAttributeUsage::Position)
562    {
563        for i in 0..vertex_buffer.vertex_count() as usize {
564            bounding_box.add_point(*position_attribute_view.get(i).unwrap());
565        }
566    }
567}
568
569fn placeholder_material() -> MaterialResource {
570    let mut material = Material::standard();
571    material.bind("diffuseTexture", PLACEHOLDER.resource());
572    MaterialResource::new_ok(Uuid::new_v4(), ResourceKind::Embedded, material)
573}
574
575impl ConstructorProvider<Node, Graph> for Mesh {
576    fn constructor() -> NodeConstructor {
577        NodeConstructor::new::<Self>()
578            .with_variant("Empty", |_| {
579                MeshBuilder::new(BaseBuilder::new()).build_node().into()
580            })
581            .with_variant("Cube", |_| {
582                MeshBuilder::new(BaseBuilder::new().with_name("Cube"))
583                    .with_surfaces(vec![SurfaceBuilder::new(surface::CUBE.resource.clone())
584                        .with_material(placeholder_material())
585                        .build()])
586                    .build_node()
587                    .into()
588            })
589            .with_variant("Cone", |_| {
590                MeshBuilder::new(BaseBuilder::new().with_name("Cone"))
591                    .with_surfaces(vec![SurfaceBuilder::new(surface::CONE.resource.clone())
592                        .with_material(placeholder_material())
593                        .build()])
594                    .build_node()
595                    .into()
596            })
597            .with_variant("Cylinder", |_| {
598                MeshBuilder::new(BaseBuilder::new().with_name("Cylinder"))
599                    .with_surfaces(vec![SurfaceBuilder::new(
600                        surface::CYLINDER.resource.clone(),
601                    )
602                    .with_material(placeholder_material())
603                    .build()])
604                    .build_node()
605                    .into()
606            })
607            .with_variant("Sphere", |_| {
608                MeshBuilder::new(BaseBuilder::new().with_name("Sphere"))
609                    .with_surfaces(vec![SurfaceBuilder::new(surface::SPHERE.resource.clone())
610                        .with_material(placeholder_material())
611                        .build()])
612                    .build_node()
613                    .into()
614            })
615            .with_variant("Quad", |_| {
616                MeshBuilder::new(BaseBuilder::new().with_name("Quad"))
617                    .with_surfaces(vec![SurfaceBuilder::new(surface::QUAD.resource.clone())
618                        .with_material(placeholder_material())
619                        .build()])
620                    .build_node()
621                    .into()
622            })
623            .with_group("Mesh")
624    }
625}
626
627impl NodeTrait for Mesh {
628    /// Returns current bounding box. Bounding box presented in *local coordinates*
629    /// WARNING: This method does *not* includes bounds of bones!
630    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
631        if self.local_bounding_box_dirty.get() {
632            let mut bounding_box = AxisAlignedBoundingBox::default();
633
634            if let BatchingMode::Static = *self.batching_mode {
635                let container = self.batch_container.0.safe_lock();
636                for batch in container.batches.values() {
637                    let data = batch.data.data_ref();
638                    extend_aabb_from_vertex_buffer(&data.vertex_buffer, &mut bounding_box);
639                }
640            } else {
641                for surface in self.surfaces.iter() {
642                    let data = surface.data();
643                    if data.is_ok() {
644                        let data = data.data_ref();
645                        extend_aabb_from_vertex_buffer(&data.vertex_buffer, &mut bounding_box);
646                    }
647                }
648            }
649
650            self.local_bounding_box.set(bounding_box);
651            self.local_bounding_box_dirty.set(false);
652        }
653
654        self.local_bounding_box.get()
655    }
656
657    /// Returns current **world-space** bounding box.
658    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
659        self.world_bounding_box.get()
660    }
661
662    fn id(&self) -> Uuid {
663        Self::type_uuid()
664    }
665
666    fn on_global_transform_changed(
667        &self,
668        new_global_transform: &Matrix4<f32>,
669        context: &mut SyncContext,
670    ) {
671        if self.surfaces.iter().any(|s| !s.bones.is_empty()) {
672            let mut world_aabb = self.local_bounding_box().transform(new_global_transform);
673
674            // Special case for skinned meshes.
675            for surface in self.surfaces.iter() {
676                for &bone in surface.bones() {
677                    if let Some(node) = context.nodes.try_borrow(bone) {
678                        world_aabb.add_point(node.global_position())
679                    }
680                }
681            }
682
683            self.world_bounding_box.set(world_aabb)
684        } else {
685            self.world_bounding_box
686                .set(self.local_bounding_box().transform(new_global_transform));
687        }
688    }
689
690    fn collect_render_data(&self, ctx: &mut RenderContext) -> RdcControlFlow {
691        if !self.should_be_rendered(ctx.frustum, ctx.render_mask) {
692            return RdcControlFlow::Continue;
693        }
694
695        if renderer::is_shadow_pass(ctx.render_pass_name) && !self.cast_shadows() {
696            return RdcControlFlow::Continue;
697        }
698
699        let sorting_index = ctx.calculate_sorting_index(self.global_position());
700
701        if let BatchingMode::Static = *self.batching_mode {
702            let mut container = self.batch_container.0.safe_lock();
703
704            if container.batches.is_empty() {
705                container.fill(self.handle(), ctx);
706            }
707
708            for batch in container.batches.values() {
709                ctx.storage.push(
710                    &batch.data,
711                    &batch.material,
712                    self.render_path(),
713                    sorting_index,
714                    SurfaceInstanceData {
715                        world_transform: Matrix4::identity(),
716                        bone_matrices: Default::default(),
717                        blend_shapes_weights: Default::default(),
718                        element_range: ElementRange::Full,
719                        node_handle: self.handle(),
720                    },
721                );
722            }
723
724            RdcControlFlow::Break
725        } else {
726            for surface in self.surfaces().iter() {
727                if !surface.data_ref().is_ok() {
728                    continue;
729                }
730                let is_skinned = !surface.bones.is_empty();
731
732                let world = if is_skinned {
733                    Matrix4::identity()
734                } else {
735                    self.global_transform()
736                };
737
738                let batching_mode = match *self.batching_mode {
739                    BatchingMode::None => BatchingMode::None,
740                    BatchingMode::Static => BatchingMode::Static,
741                    BatchingMode::Dynamic => {
742                        let surface_data_guard = surface.data_ref().data_ref();
743                        if self.blend_shapes().is_empty()
744                            && surface.bones().is_empty()
745                            && surface_data_guard.vertex_buffer.vertex_count() < 256
746                        {
747                            BatchingMode::Dynamic
748                        } else {
749                            BatchingMode::None
750                        }
751                    }
752                };
753
754                match batching_mode {
755                    BatchingMode::None => {
756                        let surface_data = surface.data_ref();
757                        let substitute_material = surface_data
758                            .data_ref()
759                            .blend_shapes_container
760                            .as_ref()
761                            .and_then(|c| c.blend_shape_storage.as_ref())
762                            .map(|texture| {
763                                let material_copy = surface.material().deep_copy();
764                                material_copy.data_ref().bind(
765                                    &self.blend_shapes_property_name,
766                                    MaterialResourceBinding::Texture(MaterialTextureBinding {
767                                        value: Some(texture.clone()),
768                                    }),
769                                );
770                                material_copy
771                            });
772
773                        ctx.storage.push(
774                            surface_data,
775                            substitute_material.as_ref().unwrap_or(surface.material()),
776                            self.render_path(),
777                            sorting_index,
778                            SurfaceInstanceData {
779                                world_transform: world,
780                                bone_matrices: surface
781                                    .bones
782                                    .iter()
783                                    .map(|bone_handle| {
784                                        if let Some(bone_node) =
785                                            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<Node> {
970        graph.add_node(self.build_node())
971    }
972}