using System.Collections; using System.Collections.Generic; using Godot; using System; namespace Rokojori { [Tool] [GlobalClass] public partial class MassRenderer:Node3D { public enum Mode { MultiMeshInstance3D, Combined, MeshInstance3D } [Export] public Mode mode = Mode.MultiMeshInstance3D; [Export] public int randomizeQueue = 1984; [ExportGroup("Mesh")] [Export] public Mesh mesh; [Export] public Material materialOveride; [ExportGroup("Layout")] [Export] public Vector3[] positions; [Export] public Vector4[] rotations; [Export] public Vector3[] scales; [ExportGroup("Outputs")] [Export] public LODMultiMeshInstance3D multiMeshNode; [Export] public Node3D meshesContainer; [Export] public MeshInstance3D combinedMesh; List _queuedTransforms = new List(); public void QueueObject( Transform3D transform ) { _queuedTransforms.Add( transform ); } public void AddQueued() { if ( positions == null ) { positions = new Vector3[0]; } if ( rotations == null ) { rotations = new Vector4[0]; } if ( scales == null ) { scales = new Vector3[0]; } if ( randomizeQueue >= 0 ) { _queuedTransforms = RandomList.Randomize( _queuedTransforms, LCG.WithSeed( randomizeQueue ) ); } var queuedPositions = Lists.Map( _queuedTransforms, t => t.Origin ); var queuedRotations = Lists.Map( _queuedTransforms, t => Math3D.QuaternionToVector4( t.Basis.GetRotationQuaternion() ) ); var queuedScales = Lists.Map( _queuedTransforms, t => t.Basis.Scale ); positions = Arrays.Concat( positions, queuedPositions.ToArray() ); rotations = Arrays.Concat( rotations, queuedRotations.ToArray() ); scales = Arrays.Concat( scales, queuedScales.ToArray() ); _queuedTransforms.Clear(); } public void Create() { AddQueued(); if ( Mode.MultiMeshInstance3D == mode ) { CreateMultiMeshes(); } else if ( Mode.MeshInstance3D == mode ) { CreateMeshes(); } else if ( Mode.Combined == mode ) { CreateCombined(); } } public void Clear() { multiMeshNode = Nodes.EnsureValid( multiMeshNode ); meshesContainer = Nodes.EnsureValid( meshesContainer ); combinedMesh = Nodes.EnsureValid( combinedMesh ); if ( multiMeshNode != null ) { multiMeshNode.Multimesh.InstanceCount = 0; } if ( meshesContainer != null ) { Nodes.RemoveAndDeleteChildren( meshesContainer ); } if ( combinedMesh != null ) { combinedMesh.Mesh = null; } } void CreateMultiMeshes() { multiMeshNode = Nodes.EnsureValid( multiMeshNode ); if ( multiMeshNode == null ) { multiMeshNode = this.CreateChild(); multiMeshNode.Multimesh = new MultiMesh(); multiMeshNode.Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D; } var mm = multiMeshNode.Multimesh; mm.Mesh = mesh; mm.InstanceCount = positions.Length; if ( materialOveride != null ) { multiMeshNode.MaterialOverride = materialOveride; } for ( int i = 0; i < positions.Length; i++ ) { var trsf = Math3D.TRS( positions[ i ], rotations[ i ], scales[ i ] ); mm.SetInstanceTransform( i, trsf ); } } void CreateMeshes() { if ( meshesContainer == null ) { meshesContainer = this.CreateChild(); } for ( int i = 0; i < positions.Length; i++ ) { var trsf = Math3D.TRS( positions[ i ], rotations[ i ], scales[ i ] ); var child = meshesContainer.CreateChild(); child.Mesh = mesh; if ( materialOveride != null ) { child.MaterialOverride = materialOveride; } child.GlobalTransform = trsf; } } void CreateCombined() { if ( meshesContainer == null ) { combinedMesh = this.CreateChild(); } var combinedMG = new MeshGeometry(); var meshMG = MeshGeometry.From( mesh as ArrayMesh ); for ( int i = 0; i < positions.Length; i++ ) { var trsf = Math3D.TRS( positions[ i ], rotations[ i ], scales[ i ] ); combinedMG.Add( meshMG, trsf ); } if ( materialOveride != null ) { combinedMesh.MaterialOverride = materialOveride; } } } }