using System.Collections; using System.Collections.Generic; using Godot; using System; namespace Rokojori { [Tool] [GlobalClass] public partial class MeshCombiner:Node3D { [Export] public Node3D[] sourceNodes = []; [ExportToolButton( "Combine")] public Callable CombineButton => Callable.From( Combine ); [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 = []; MultiMap<Mesh,int,MeshGeometry> _meshGeometryCache = new MultiMap<Mesh,int,MeshGeometry>(); 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<Transformable<MeshSurface>> _surfaces; List<Material> _materials; MapList<Material,Transformable<MeshSurface>> _materiaList = new MapList<Material, Transformable<MeshSurface>>() ; Dictionary<Material,Transform2D> _uvTransform = new Dictionary<Material, Transform2D>(); public void Combine() { GrabSurfaces(); GrabMaterials(); CombineMaterials(); CombineMeshes(); } void GrabSurfaces() { _surfaces = new List<Transformable<MeshSurface>>(); foreach ( var n in sourceNodes ) { MeshExtractor.ExtractSurfacesInHierarchy( n, _surfaces ); } } void GrabMaterials() { _materials = new List<Material>(); _materiaList = new MapList<Material, Transformable<MeshSurface>>(); var set = new HashSet<Material>(); _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; _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<MeshInstance3D>(); } outputMesh.Mesh = arrayMesh; outputMaterials = _materials.ToArray(); } } }