using System.Collections; using System.Collections.Generic; using Godot; using System; namespace Rokojori { [Tool] [GlobalClass] public partial class MeshCombiner:Node3D { [Export] public Node3D[] sourceNodes; [ExportGroup( "Mesh")] [Export] public bool combineMeshes = true; public enum UVCombineMode { Keep, Adjust_To_Combined_Material } [Export] public UVCombineMode uVCombineMode = UVCombineMode.Adjust_To_Combined_Material; [Export] public Node3D pivot; [ExportGroup( "Material")] [Export] public bool combineMaterials = true; public enum TextureSizeMode { KeepOriginal, Custom } [Export] public TextureSizeMode textureSizeMode = TextureSizeMode.Custom; [Export] public Vector2I customTextureSize = new Vector2I( 1024, 1024 ); [ExportGroup( "Output")] [Export] public MeshInstance3D outputMesh; [Export] public Material[] outputMaterials; [Export] public bool combine = false; public override void _Process( double delta ) { if ( ! combine ) { return; } combine = false; Combine(); } MultiMap _meshGeometryCache = new MultiMap(); MeshGeometry GetMeshGeometry( MeshSurface surface ) { if ( ! _meshGeometryCache.Has( surface.mesh, surface.index ) ) { var mg = MeshGeometry.From( surface.mesh as ArrayMesh, null, surface.index ); _meshGeometryCache.Set( surface.mesh, surface.index, mg ); this.LogInfo( "Created mesh with triangles:", mg.numTriangles ); } return _meshGeometryCache[ surface.mesh ][ surface.index ]; } List> _surfaces; List _materials; MapList> _materiaList = new MapList>() ; Dictionary _uvTransform = new Dictionary(); public void Combine() { GrabSurfaces(); GrabMaterials(); CombineMaterials(); CombineMeshes(); } void GrabSurfaces() { _surfaces = new List>(); foreach ( var n in sourceNodes ) { MeshExtractor.ExtractSurfacesInHierarchy( n, _surfaces ); } } void GrabMaterials() { _materials = new List(); _materiaList = new MapList>(); var set = new HashSet(); _surfaces.ForEach( ( s )=> { _materiaList.Add( s.item.material, s ); if ( set.Contains( s.item.material ) ) { return; } set.Add( s.item.material ); _materials.Add( s.item.material ); } ); } void CombineMaterials() { } void CombineMeshes() { var arrayMesh = new ArrayMesh(); this.LogInfo( "Combining", _surfaces.Count, "meshes" ); var index = 0; var nm = 0; var max = 100; _materials.ForEach( ( m )=> { Transform2D? uvTransform = _uvTransform.ContainsKey( m ) ? _uvTransform[ m ] : null; var surfaces = _materiaList[ m ]; this.LogInfo( "Combining for Material", m, surfaces.Count, "meshes" ); var meshGeometry = new MeshGeometry(); surfaces.ForEach( ( s )=> { var smg = GetMeshGeometry( s.item ).Clone(); if ( uvTransform != null ) { smg.ApplyUVTransform( (Transform2D) uvTransform ); } var trsf = s.transform; if ( pivot != null ) { trsf.Origin -= pivot.GlobalPosition; } smg.ApplyTransform( trsf ); meshGeometry.Add( smg ); } ); meshGeometry.GenerateMesh( Mesh.PrimitiveType.Triangles, arrayMesh ); arrayMesh.SurfaceSetMaterial( index, m ); index ++; } ); if ( outputMesh == null ) { outputMesh = this.CreateChild(); } outputMesh.Mesh = arrayMesh; outputMaterials = _materials.ToArray(); } } }