rj-action-library/Runtime/Procedural/Mesh/MassRenderer.cs

217 lines
4.7 KiB
C#

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<Transform3D> _queuedTransforms = new List<Transform3D>();
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<Transform3D>.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<LODMultiMeshInstance3D>();
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<Node3D>();
}
for ( int i = 0; i < positions.Length; i++ )
{
var trsf = Math3D.TRS( positions[ i ], rotations[ i ], scales[ i ] );
var child = meshesContainer.CreateChild<MeshInstance3D>();
child.Mesh = mesh;
if ( materialOveride != null )
{
child.MaterialOverride = materialOveride;
}
child.GlobalTransform = trsf;
}
}
void CreateCombined()
{
if ( meshesContainer == null )
{
combinedMesh = this.CreateChild<MeshInstance3D>();
}
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;
}
}
}
}