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

205 lines
4.3 KiB
C#
Raw Normal View History

2025-01-03 12:09:23 +00:00
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<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;
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<MeshInstance3D>();
}
outputMesh.Mesh = arrayMesh;
outputMaterials = _materials.ToArray();
}
}
}