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