261 lines
6.1 KiB
C#
261 lines
6.1 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using System;
|
|
using System.Linq;
|
|
|
|
|
|
|
|
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 = new Vector3[ 0 ];
|
|
|
|
[Export]
|
|
public Vector4[] rotations = new Vector4[ 0 ];
|
|
|
|
[Export]
|
|
public Vector3[] scales = new Vector3[ 0 ];
|
|
|
|
[ExportGroup("Outputs")]
|
|
[Export]
|
|
public LODMultiMeshInstance3D[] multiMeshNodes;
|
|
|
|
[Export]
|
|
public float multiMeshSplitSize = 25;
|
|
|
|
[Export]
|
|
public Vector3 multiMeshSplitScatterRelative = new Vector3( 2, 0, 2 );
|
|
|
|
[Export]
|
|
public Vector3 multiMeshSplitScatterScale = new Vector3( 10, 10, 10 );
|
|
|
|
Dictionary<Vector3I,LODMultiMeshInstance3D> multiMeshMapping = new Dictionary<Vector3I, LODMultiMeshInstance3D>();
|
|
|
|
[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()
|
|
{
|
|
if ( multiMeshNodes != null )
|
|
{
|
|
for ( int i = 0 ; i < multiMeshNodes.Length; i++ )
|
|
{
|
|
multiMeshNodes[ i ] = Nodes.EnsureValid( multiMeshNodes[ i ] );
|
|
|
|
if ( multiMeshNodes[ i ] != null )
|
|
{
|
|
Nodes.RemoveAndDelete( multiMeshNodes[ i ] );
|
|
}
|
|
}
|
|
|
|
multiMeshNodes = [];
|
|
}
|
|
|
|
meshesContainer = Nodes.EnsureValid( meshesContainer );
|
|
combinedMesh = Nodes.EnsureValid( combinedMesh );
|
|
|
|
|
|
if ( meshesContainer != null )
|
|
{
|
|
Nodes.RemoveAndDeleteChildren( meshesContainer );
|
|
}
|
|
|
|
if ( combinedMesh != null )
|
|
{
|
|
combinedMesh.Mesh = null;
|
|
}
|
|
}
|
|
|
|
void CreateMultiMeshes()
|
|
{
|
|
|
|
var instancesSorted = new MapList<Vector3I,int>();
|
|
|
|
for ( int i = 0; i < positions.Length; i++ )
|
|
{
|
|
var floatIndex = ( positions[ i ] / multiMeshSplitSize );
|
|
floatIndex += Noise.Perlin3( positions[ i ] * multiMeshSplitScatterScale ) * multiMeshSplitScatterRelative;
|
|
var index = floatIndex.RoundToInt();
|
|
|
|
instancesSorted.Add( index, i );
|
|
}
|
|
|
|
var keys = instancesSorted.Keys.ToList();
|
|
var numMultiMeshes = keys.Count;
|
|
|
|
multiMeshNodes = new LODMultiMeshInstance3D[ numMultiMeshes ];
|
|
|
|
for ( int i = 0; i < numMultiMeshes; i++ )
|
|
{
|
|
var multiMeshNode = this.CreateChild<LODMultiMeshInstance3D>();
|
|
multiMeshNode.Multimesh = new MultiMesh();
|
|
multiMeshNode.Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
|
|
|
|
multiMeshNodes[ i ] = multiMeshNode;
|
|
|
|
var mm = multiMeshNode.Multimesh;
|
|
var meshIndices = instancesSorted[ keys[ i ] ];
|
|
|
|
mm.Mesh = mesh;
|
|
mm.InstanceCount = meshIndices.Count;
|
|
|
|
if ( materialOveride != null )
|
|
{
|
|
multiMeshNode.MaterialOverride = materialOveride;
|
|
}
|
|
|
|
this.LogInfo( i, ">>", keys[ i ], ">>", meshIndices.Count );
|
|
|
|
for ( int j = 0; j < meshIndices.Count; j++ )
|
|
{
|
|
var index = meshIndices[ j ];
|
|
var trsf = Math3D.TRS( positions[ index ], rotations[ index ], scales[ index ] );
|
|
mm.SetInstanceTransform( j, 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;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
} |