Baker Updates

This commit is contained in:
Josef 2025-05-10 22:56:23 +02:00
parent ae58b96fd8
commit 4f496cc7cc
40 changed files with 1329 additions and 257 deletions

View File

@ -8,6 +8,31 @@ namespace Rokojori
{ {
public class Bytes public class Bytes
{ {
public static string ConvertToString( ulong numBytes, int basis = 1000 )
{
var unitIndex = 0;
var units = new List<string>()
{
"Bytes",
"KB",
"MB",
"GB",
"TB"
};
double num = numBytes;
while ( num >= 1000 && unitIndex < ( units.Count - 1 ) )
{
num = num / 1000.0;
unitIndex ++;
}
var fNum = (float) num;
return RegexUtility._FFF( fNum ) + " " + units[ unitIndex ];
}
public static byte SetBit( byte value, int position ) public static byte SetBit( byte value, int position )
{ {

View File

@ -13,6 +13,11 @@ namespace Rokojori
{ {
this.min = min; this.min = min;
this.max = max; this.max = max;
}
public static Box2 With( float width, float height, float x = 0, float y = 0 )
{
return new Box2( new Vector2( x, y ), new Vector2( x + width, y + height ) );
} }
public Box2() public Box2()

View File

@ -189,13 +189,24 @@ namespace Rokojori
return value * 0.5f + 0.5f; return value * 0.5f + 0.5f;
} }
public static int NextPowerOfTwo( int num ) public static int NextPowerOfTwoExponent( int num )
{ {
var p = Exponent( 2, num ); var p = Exponent( 2, num );
return Mathf.CeilToInt( p ); return Mathf.CeilToInt( p );
} }
public static int NextPowerOfTwoExponent( float num )
{
return NextPowerOfTwoExponent( Mathf.RoundToInt( num ) );
}
public static int NextPowerOfTwo( float num )
{
var exponent = NextPowerOfTwoExponent( num );
return 1 << exponent;
}
public static float Repeat( float value, float length ) public static float Repeat( float value, float length )
{ {
while ( value > length ) while ( value > length )

View File

@ -62,7 +62,7 @@ namespace Rokojori
if ( material == null ) if ( material == null )
{ {
n.LogInfo( "No material found" ); // n.LogInfo( "No material found" );
return; return;
} }
@ -72,7 +72,7 @@ namespace Rokojori
if ( material is StandardMaterial3D sm ) if ( material is StandardMaterial3D sm )
{ {
n.LogInfo( "StandardMaterial3D found" ); // n.LogInfo( "StandardMaterial3D found" );
appliedMaterial.AlbedoColor = sm.AlbedoColor; appliedMaterial.AlbedoColor = sm.AlbedoColor;
appliedMaterial.AlbedoTexture = sm.AlbedoTexture; appliedMaterial.AlbedoTexture = sm.AlbedoTexture;
@ -90,7 +90,7 @@ namespace Rokojori
} }
else else
{ {
n.LogInfo( "No StandardMaterial3D found", material.GetType().Name ); // n.LogInfo( "No StandardMaterial3D found", material.GetType().Name );
} }

View File

@ -67,7 +67,7 @@ namespace Rokojori
if ( material == null ) if ( material == null )
{ {
n.LogInfo( "No material found" ); // n.LogInfo( "No material found" );
return; return;
} }
@ -81,7 +81,7 @@ namespace Rokojori
if ( material is StandardMaterial3D sm ) if ( material is StandardMaterial3D sm )
{ {
n.LogInfo( "StandardMaterial3D found" ); // n.LogInfo( "StandardMaterial3D found" );
appliedMaterial.SetShaderParameter( "use_normalmap", sm.NormalTexture != null ); appliedMaterial.SetShaderParameter( "use_normalmap", sm.NormalTexture != null );
appliedMaterial.SetShaderParameter( "normal_texture", sm.NormalTexture ); appliedMaterial.SetShaderParameter( "normal_texture", sm.NormalTexture );
@ -99,7 +99,7 @@ namespace Rokojori
} }
else else
{ {
n.LogInfo( "No StandardMaterial3D found", material.GetType().Name ); // n.LogInfo( "No StandardMaterial3D found", material.GetType().Name );
} }

View File

@ -92,7 +92,7 @@ namespace Rokojori
if ( material == null ) if ( material == null )
{ {
n.LogInfo( "No material found" ); // n.LogInfo( "No material found" );
return; return;
} }
@ -103,7 +103,7 @@ namespace Rokojori
if ( material is StandardMaterial3D sm ) if ( material is StandardMaterial3D sm )
{ {
n.LogInfo( "StandardMaterial3D found" ); // n.LogInfo( "StandardMaterial3D found" );
SetChannel( "A", appliedMaterial, sm.AOTexture, 0 ); SetChannel( "A", appliedMaterial, sm.AOTexture, 0 );
SetChannel( "B", appliedMaterial, sm.RoughnessTexture, 1 ); SetChannel( "B", appliedMaterial, sm.RoughnessTexture, 1 );
@ -128,7 +128,7 @@ namespace Rokojori
} }
else else
{ {
n.LogInfo( "No StandardMaterial3D found", material.GetType().Name ); // n.LogInfo( "No StandardMaterial3D found", material.GetType().Name );
} }

View File

@ -67,7 +67,7 @@ namespace Rokojori
if ( material == null ) if ( material == null )
{ {
n.LogInfo( "No material found" ); // n.LogInfo( "No material found" );
return; return;
} }
@ -78,7 +78,7 @@ namespace Rokojori
if ( material is StandardMaterial3D sm ) if ( material is StandardMaterial3D sm )
{ {
n.LogInfo( "StandardMaterial3D found" ); // n.LogInfo( "StandardMaterial3D found" );
appliedMaterial.SetShaderParameter( "uv1_scale", sm.Uv1Scale ); appliedMaterial.SetShaderParameter( "uv1_scale", sm.Uv1Scale );
appliedMaterial.SetShaderParameter( "uv1_offset", sm.Uv1Offset ); appliedMaterial.SetShaderParameter( "uv1_offset", sm.Uv1Offset );
@ -86,7 +86,7 @@ namespace Rokojori
} }
else else
{ {
n.LogInfo( "No StandardMaterial3D found", material.GetType().Name ); // n.LogInfo( "No StandardMaterial3D found", material.GetType().Name );
} }

View File

@ -143,6 +143,7 @@ namespace Rokojori
} }
mg.ApplyTranslation( -mb.targetPivot );
mb.X_outputMesh.Mesh = mg.GenerateMesh(); mb.X_outputMesh.Mesh = mg.GenerateMesh();
} }

View File

@ -159,6 +159,7 @@ namespace Rokojori
} }
mg.ApplyTranslation( -mb.targetPivot );
mb.X_outputMesh.Mesh = mg.GenerateMesh(); mb.X_outputMesh.Mesh = mg.GenerateMesh();

View File

@ -15,7 +15,7 @@ namespace Rokojori
public override int GetNumViews() public override int GetNumViews()
{ {
return 2; return useDoubleSidedMaterial ? 1 : 2;
} }
public override void CreateBakers() public override void CreateBakers()
@ -24,7 +24,6 @@ namespace Rokojori
var distance = multiBaker.GetCameraDistance(); var distance = multiBaker.GetCameraDistance();
var outputScale = multiBaker.GetOutputScale(); var outputScale = multiBaker.GetOutputScale();
RJLog.Log( "outputScale", outputScale );
var bakerCameras = multiBaker.bakerCameras; var bakerCameras = multiBaker.bakerCameras;
var mb = multiBaker; var mb = multiBaker;
@ -62,6 +61,8 @@ namespace Rokojori
} }
mg.ApplyTranslation( -mb.targetPivot );
mb.X_outputMesh.Mesh = mg.GenerateMesh(); mb.X_outputMesh.Mesh = mg.GenerateMesh();
} }

View File

@ -13,7 +13,7 @@ namespace Rokojori
public partial class MultiBaker:Node public partial class MultiBaker:Node
{ {
[ExportToolButton( "Bake")] [ExportToolButton( "Bake")]
public Callable BakeButton => Callable.From( () => StartBaking() ); public Callable BakeButton => Callable.From( () => Bake() );
[Export] [Export]
public bool cleanUpAfterBaking = true; public bool cleanUpAfterBaking = true;
@ -21,31 +21,10 @@ namespace Rokojori
[Export] [Export]
public _XX_MultiBakeMode bakeMode; public _XX_MultiBakeMode bakeMode;
public enum MaterialMode
{
Full_Seperated,
Simple_Prebaked
}
// [ExportGroup("Textures")]
[Export] [Export]
public _XX_MultiTextureBaker textureBaker; public _XX_MultiTextureBaker textureBaker;
// [Export]
// public MaterialMode materialMode;
// [Export]
// public int dilationRadius = 64;
// [ExportGroup("Material/Full Seperated")]
// [Export]
// public bool mmfs_Normals = true;
// [Export]
// public bool mmfs_Depth = true;
// [Export]
// public bool mmfs_ORM = true;
[Export] [Export]
public BakingViewSettings viewSettings; public BakingViewSettings viewSettings;
@ -61,9 +40,6 @@ namespace Rokojori
public Vector3 targetPivot; public Vector3 targetPivot;
public float cameraZoom public float cameraZoom
{ {
get get
@ -150,10 +126,12 @@ namespace Rokojori
[Export] [Export]
public bool X_baking = false; public bool X_baking = false;
public void StartBaking() public async Task Bake()
{ {
Initialize(); Initialize();
Bake(); await CreateBakes();
return;
} }
public void Initialize() public void Initialize()
@ -234,7 +212,12 @@ namespace Rokojori
// _bakerCameras.ForEach( b => b.viewport.en) // _bakerCameras.ForEach( b => b.viewport.en)
Nodes.RemoveAndDeleteChildren( X_bakingTargetContainer ); Nodes.RemoveAndDeleteChildren( X_bakingTargetContainer );
target.DeepCopyTo( X_bakingTargetContainer ); var root = (Node3D)target.DeepCopyTo( X_bakingTargetContainer );
root.GlobalPosition = Vector3.Zero;
root.SetGlobalQuaternion( Quaternion.Identity );
root.Scale = Vector3.One;
_targetIsInInitialState = true; _targetIsInInitialState = true;
@ -272,7 +255,7 @@ namespace Rokojori
} }
public async Task Bake() public async Task CreateBakes()
{ {
if ( X_baking ) if ( X_baking )
{ {
@ -307,39 +290,9 @@ namespace Rokojori
var passes = textureBaker.GetPasses( this ); var passes = textureBaker.GetPasses( this );
// X_setBakingMaterials.SetTarget( X_bakingTargetContainer );
// var bakingMaterialModes = new List<BakingMaterialMode>();
// var preview_QuickMaterial = MaterialMode.Simple_Prebaked == materialMode;
// bakeMode.CreateMaterial( preview_QuickMaterial );
bakeMode.CreateMaterial( passes ); bakeMode.CreateMaterial( passes );
// if ( preview_QuickMaterial )
// {
// bakingMaterialModes.Add( BakingMaterialMode.Preview );
// }
// else
// {
// bakingMaterialModes.Add( BakingMaterialMode.Albedo );
// if ( mmfs_Normals )
// {
// bakingMaterialModes.Add( BakingMaterialMode.Normals );
// }
// if ( mmfs_Depth )
// {
// bakingMaterialModes.Add( BakingMaterialMode.Depth );
// }
// if ( mmfs_ORM )
// {
// bakingMaterialModes.Add( BakingMaterialMode.ORM );
// }
// }
this.LogInfo( "Prepared baking modes" ); this.LogInfo( "Prepared baking modes" );
X_textureMerger.textureSize = outputTextureSize; X_textureMerger.textureSize = outputTextureSize;
@ -347,13 +300,6 @@ namespace Rokojori
X_textureMerger.CreateLayout(); X_textureMerger.CreateLayout();
// this.LogInfo( "Prepared texture merger" );
// var fovDistance = viewSettings.fovDistance.ComputeFOVDistance(
// var objectDistance = GetCameraDistance();
// this.LogInfo( "Set Camera Distance", objectDistance );
for ( int i = 0; i < passes.Count; i++ ) for ( int i = 0; i < passes.Count; i++ )
{ {
ResetOriginalTargetState(); ResetOriginalTargetState();
@ -366,34 +312,7 @@ namespace Rokojori
bakeMode.AssignMaterial( passes ); bakeMode.AssignMaterial( passes );
// for ( int i = 0; i < bakingMaterialModes.Count; i++ ) X_outputMesh.GlobalPosition = target.GlobalPosition;// - targetPivot;
// {
// this.LogInfo( "Baking mode:", bakingMaterialModes[ i ] );
// X_setBakingMaterials.mode = bakingMaterialModes[ i ];
// X_setBakingMaterials.ApplyBakingMaterials( objectDistance, _targetBoundingSphere.radius );
// this.LogInfo( "Materials changed:", bakingMaterialModes[ i ] );
// _bakers.ForEach( b => b.ApplyCameraSettings() );
// await this.RequestNextFrame();
// X_textureDilate.viewport = X_textureMerger.X_textureMergerViewport;
// Texture2D texture = await X_textureDilate.Grab();
// this.LogInfo( "Assigning Texture", bakingMaterialModes[ i ] );
// bakeMode.AssignMaterial( bakingMaterialModes[ i ], texture );
// this.LogInfo( "Baking done:", bakingMaterialModes[ i ] );
// await this.RequestNextFrame();
// }
// await this.RequestNextFrame();
X_outputMesh.GlobalPosition = target.GlobalPosition - targetPivot;
X_outputMesh.Scale = Vector3.One * cameraZoom; X_outputMesh.Scale = Vector3.One * cameraZoom;
@ -424,27 +343,6 @@ namespace Rokojori
return Nodes.AllIn<SubViewport>( X_views, null, false ); return Nodes.AllIn<SubViewport>( X_views, null, false );
} }
// public void CacheTexture( BakingMaterialMode mode, Texture2D texture )
// {
// if ( BakingMaterialMode.Albedo == mode )
// {
// X_bakedTextureAlbedo = texture;
// }
// else if ( BakingMaterialMode.Normals == mode )
// {
// X_bakedTextureNormal = texture;
// }
// else if ( BakingMaterialMode.ORM == mode )
// {
// X_bakedTextureORM = texture;
// }
// else if ( BakingMaterialMode.Depth == mode )
// {
// X_bakedTextureDepth = texture;
// }
// }
public void CleanUp() public void CleanUp()
{ {
var mesh = X_outputMesh; var mesh = X_outputMesh;

View File

@ -10,6 +10,9 @@ namespace Rokojori
[Tool][GlobalClass] [Tool][GlobalClass]
public partial class _XX_MultiBakeModeBillboardBase:_XX_MultiBakeMode public partial class _XX_MultiBakeModeBillboardBase:_XX_MultiBakeMode
{ {
[Export]
public bool useDoubleSidedMaterial = false;
public override void CreateMaterial( List<_XX_BakingPass> passes ) public override void CreateMaterial( List<_XX_BakingPass> passes )
{ {
var preview = passes.Find( p => p.ContainsBakingOutput( BakingTargetType.Albedo ) ) == null; var preview = passes.Find( p => p.ContainsBakingOutput( BakingTargetType.Albedo ) ) == null;
@ -25,6 +28,11 @@ namespace Rokojori
material.AlphaAntialiasingEdge = 0.95f; material.AlphaAntialiasingEdge = 0.95f;
material.NormalEnabled = ! preview; material.NormalEnabled = ! preview;
if ( useDoubleSidedMaterial )
{
material.CullMode = BaseMaterial3D.CullModeEnum.Disabled;
}
Materials.Set( mb.X_outputMesh, material ); Materials.Set( mb.X_outputMesh, material );
} }

View File

@ -41,10 +41,16 @@ namespace Rokojori
public void SetDilationRadius( Vector2 size ) public void SetDilationRadius( Vector2 size )
{ {
SetDilationRadius( Mathf.RoundToInt( Mathf.Max( size.X, size.Y ) ) ); SetDilationRadius( Mathf.RoundToInt( Mathf.Max( size.X, size.Y ) ) );
} }
public bool skipMode = false;
public async Task<Texture2D> Grab( bool srgb, bool alpha, bool mipmaps = false ) public async Task<Texture2D> Grab( bool srgb, bool alpha, bool mipmaps = false )
{ {
this.LogInfo( "Current Render Device Memory", RDContext.Current().GetMemoryInfo() );
var updateMode = viewport.RenderTargetUpdateMode; var updateMode = viewport.RenderTargetUpdateMode;
if ( updateMode != SubViewport.UpdateMode.Always ) if ( updateMode != SubViewport.UpdateMode.Always )
@ -54,19 +60,30 @@ namespace Rokojori
viewport.RenderTargetUpdateMode = updateMode; viewport.RenderTargetUpdateMode = updateMode;
} }
if ( skipMode )
{
this.LogInfo( "Skipping Creation" );
var skipImage = viewport.GetTexture().GetImage();
var skipBuffer = TextureCombinerBuffer.From( ImageTexture.CreateFromImage( skipImage ), -1 );
var skipTexture = skipBuffer.CreateImageTexture( alpha, mipmaps );
return skipTexture;
}
var viewPortFormat = RDTextureFormats.GetDataFormat( viewport ); var viewPortFormat = RDTextureFormats.GetDataFormat( viewport );
var viewPortData = viewport.GetTexture().GetImage().GetData(); var viewPortData = viewport.GetTexture().GetImage().GetData();
var viewPortSize = viewport.Size; var viewPortSize = viewport.Size;
this.LogInfo( "Grabbed viewport context", viewPortFormat, viewPortSize );
this.LogInfo( "Creating context" ); // this.LogInfo( "Grabbed viewport context", viewPortFormat, viewPortSize );
// this.LogInfo( "Creating context" );
var ctx = RDContext.Local(); var ctx = RDContext.Local();
ctx.computeSize = viewPortSize; ctx.computeSize = viewPortSize;
// ctx.messageLogLevel = Messages.GetLevel( MessageType.Verbose ); // ctx.messageLogLevel = Messages.GetLevel( MessageType.Verbose );
this.LogInfo( "Creating textures" ); // this.LogInfo( "Creating textures" );
var bufferTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat ); var bufferTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat );
var bufferTexture2 = RDTexture.Create( ctx, viewport.Size, viewPortFormat ); var bufferTexture2 = RDTexture.Create( ctx, viewport.Size, viewPortFormat );
@ -77,11 +94,11 @@ namespace Rokojori
var inputTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat ); var inputTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat );
inputTexture.SetData( viewPortData ); inputTexture.SetData( viewPortData );
this.LogInfo( "Creating graph" ); // this.LogInfo( "Creating graph" );
var graph = CreateGraph( ctx, inputTexture, initTexture, bufferTexture, bufferTexture2, resultTexture ); var graph = CreateGraph( ctx, inputTexture, initTexture, bufferTexture, bufferTexture2, resultTexture );
this.LogInfo( "Process graph" ); // this.LogInfo( "Process graph" );
graph.ProcessForView(); graph.ProcessForView();
ctx.SubmitAndSync(); ctx.SubmitAndSync();
@ -97,7 +114,7 @@ namespace Rokojori
await this.RequestNextFrame(); await this.RequestNextFrame();
this.LogInfo( "Copying texture:", format ); // this.LogInfo( "Copying texture:", format );
var image = Image.CreateFromData( width, height, false, format, data ); var image = Image.CreateFromData( width, height, false, format, data );
@ -115,7 +132,15 @@ namespace Rokojori
target = texture; target = texture;
ctx.CleanUp(); // ctx.messageLogLevel = Messages.GetLevel( MessageType.Verbose );
// ctx.CleanUp();
// ctx.messageLogLevel = Messages.GetLevel( MessageType.Info );
ctx.CleanUpAndFree();
GC.Collect();
GC.WaitForPendingFinalizers();
return texture; return texture;

View File

@ -242,7 +242,7 @@ namespace Rokojori
var uvRectangle = GetUVRectangle( alignment, i ); var uvRectangle = GetUVRectangle( alignment, i );
RJLog.Log( "Set Texture" + ( i + 1 ), uvRectangle.min, uvRectangle.max ); // RJLog.Log( "Set Texture" + ( i + 1 ), uvRectangle.min, uvRectangle.max );
SetMeshCoordinates( meshInstance, uvRectangle, i ); SetMeshCoordinates( meshInstance, uvRectangle, i );
var dilatedMaterial = new DilationDrawerMaterial(); var dilatedMaterial = new DilationDrawerMaterial();
@ -310,7 +310,18 @@ namespace Rokojori
mesh.GlobalPosition = new Vector3( start.X + size.X/2, start.Y + size.Y/2, -1 ); mesh.GlobalPosition = new Vector3( start.X + size.X/2, start.Y + size.Y/2, -1 );
RJLog.Log( "Set Mesh", index, "Size:", size, "Min:", min, ">>", start, "Max:", max, ">>", end ); // RJLog.Log( "Set Mesh", index, "Size:", size, "Min:", min, ">>", start, "Max:", max, ">>", end );
}
public static Box2 GetUVAlignmentBoxFor( Vector2I alignment, int index )
{
var x = index % alignment.X;
var y = index / alignment.X;
var sizeX = 1f / alignment.X;
var sizeY = 1f / alignment.Y;
return Box2.With( sizeX, sizeY, x * sizeX, y * sizeY );
} }
public static Vector2I ComputeTextureAlignment( int numElements ) public static Vector2I ComputeTextureAlignment( int numElements )

View File

@ -0,0 +1,296 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
namespace Rokojori
{
public abstract class MaterialSurfaceContainer
{
public enum MaterialSlot
{
None,
MeshSurface,
MeshSurfaceOverride,
Override,
Overlay
}
protected Node3D _owner;
protected int _surfaceIndex;
public int surfaceIndex => _surfaceIndex;
protected MaterialSurfaceContainer( Node3D owner, int surfaceIndex )
{
_owner = owner;
_surfaceIndex = surfaceIndex;
}
public abstract MaterialSlot GetActiveMaterialSlot();
public abstract Material GetMaterialInSlot( MaterialSlot slot );
public abstract void SetMaterialInSlot( MaterialSlot slot, Material material );
public void SetActiveMaterial( Material material )
{
SetMaterialInSlot( GetActiveMaterialSlot(), material );
}
public Material GetActiveMaterial()
{
return GetMaterialInSlot( GetActiveMaterialSlot() );
}
protected abstract void _MakeUnique( bool materials );
public void MakeUnique( bool materials )
{
if ( ! isOwner )
{
return;
}
_MakeUnique( materials );
}
public bool isOwner => _surfaceIndex == -1;
public virtual List<MaterialSurfaceContainer> GetOwnedSurfaceContainers()
{
if ( ! isOwner )
{
return null;
}
var surfaces = numSurfaces;
var type = GetType();
var list = new List<MaterialSurfaceContainer>();
for ( int i = 0; i < surfaces; i++ )
{
var surfaceContainer = ReflectionHelper.Create<MaterialSurfaceContainer>( type, _owner, i );
list.Add( surfaceContainer );
}
return list;
}
public virtual void ForAllSurfaces( Action<MaterialSurfaceContainer> action )
{
var surfaces = GetOwnedSurfaceContainers();
surfaces.ForEach( s => action( s ) );
}
public abstract int numSurfaces { get; }
}
public abstract class MaterialSurfaceContainer<T>:MaterialSurfaceContainer where T:Node3D
{
public T node => (T)_owner;
protected MaterialSurfaceContainer( Node3D owner, int surfaceIndex ):base( owner, surfaceIndex ){}
}
public class MeshSurfaceContainer: MaterialSurfaceContainer<MeshInstance3D>
{
public MeshSurfaceContainer( MeshInstance3D owner, int surfaceIndex = -1 ):base( owner, surfaceIndex ){}
public override int numSurfaces => node == null || node.Mesh == null ? -1 : node.Mesh.GetSurfaceCount();
public override MeshSurfaceContainer.MaterialSlot GetActiveMaterialSlot()
{
if ( node.MaterialOverride != null )
{
return MeshSurfaceContainer.MaterialSlot.Override;
}
if ( node.Mesh == null || surfaceIndex == -1 )
{
return MeshSurfaceContainer.MaterialSlot.None;
}
if ( node.GetSurfaceOverrideMaterial( surfaceIndex ) != null )
{
return MeshSurfaceContainer.MaterialSlot.MeshSurfaceOverride;
}
var material = node.Mesh.SurfaceGetMaterial( surfaceIndex );
return material == null ? MeshSurfaceContainer.MaterialSlot.None : MeshSurfaceContainer.MaterialSlot.MeshSurface;
}
public override void SetMaterialInSlot( MaterialSlot slot, Material material )
{
if ( surfaceIndex == -1 || MaterialSlot.None == slot )
{
return;
}
if ( MaterialSlot.MeshSurface == slot )
{
node.Mesh.SurfaceSetMaterial( surfaceIndex, material );
}
else if ( MaterialSlot.MeshSurfaceOverride == slot )
{
node.SetSurfaceOverrideMaterial( surfaceIndex, material );
}
else if ( MaterialSlot.Override == slot )
{
node.MaterialOverride = material;
}
else if ( MaterialSlot.Overlay == slot )
{
node.MaterialOverlay = material;
}
}
public override Material GetMaterialInSlot( MaterialSlot slot )
{
if ( MaterialSlot.None == slot )
{
return null;
}
else if ( MaterialSlot.MeshSurface == slot )
{
return node.Mesh.SurfaceGetMaterial( surfaceIndex );
}
else if ( MaterialSlot.MeshSurfaceOverride == slot )
{
return node.GetSurfaceOverrideMaterial( surfaceIndex );
}
else if ( MaterialSlot.Override == slot )
{
return node.MaterialOverride;
}
else if ( MaterialSlot.Overlay == slot )
{
return node.MaterialOverlay;
}
return null;
}
protected override void _MakeUnique( bool materials )
{
if ( node.Mesh == null )
{
return;
}
node.Mesh = (Mesh)node.Mesh.Duplicate();
if ( ! materials )
{
return;
}
for ( int i = 0; i < numSurfaces; i++ )
{
var m = node.Mesh.SurfaceGetMaterial( i );
node.Mesh.SurfaceSetMaterial( i, (Material)m.Duplicate() );
}
}
}
public class MultiMeshSurfaceContainer: MaterialSurfaceContainer<MultiMeshInstance3D>
{
public MultiMeshSurfaceContainer( MultiMeshInstance3D mi, int surfaceIndex = -1 ):base( mi, surfaceIndex ){}
public override int numSurfaces => node == null || node.Multimesh == null || node.Multimesh.Mesh == null ? -1 :
node.Multimesh.Mesh.GetSurfaceCount();
public override MeshSurfaceContainer.MaterialSlot GetActiveMaterialSlot()
{
if ( node.MaterialOverride != null )
{
return MeshSurfaceContainer.MaterialSlot.Override;
}
if ( node.Multimesh == null || node.Multimesh.Mesh == null || surfaceIndex == -1 )
{
return MeshSurfaceContainer.MaterialSlot.None;
}
var material = node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex );
return material == null ? MeshSurfaceContainer.MaterialSlot.None : MeshSurfaceContainer.MaterialSlot.MeshSurface;
}
public override void SetMaterialInSlot( MaterialSlot slot, Material material )
{
if ( surfaceIndex == -1 || MaterialSlot.None == slot )
{
return;
}
if ( MaterialSlot.MeshSurface == slot )
{
node.Multimesh.Mesh.SurfaceSetMaterial( surfaceIndex, material );
}
else if ( MaterialSlot.Override == slot )
{
node.MaterialOverride = material;
}
else if ( MaterialSlot.Overlay == slot )
{
node.MaterialOverlay = material;
}
}
public override Material GetMaterialInSlot( MaterialSlot slot )
{
if ( MaterialSlot.None == slot )
{
return null;
}
else if ( MaterialSlot.MeshSurface == slot )
{
return node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex );
}
else if ( MaterialSlot.Override == slot )
{
return node.MaterialOverride;
}
else if ( MaterialSlot.Overlay == slot )
{
return node.MaterialOverlay;
}
return null;
}
protected override void _MakeUnique( bool materials )
{
if ( node.Multimesh == null || node.Multimesh.Mesh == null )
{
return;
}
node.Multimesh.Mesh = (Mesh)node.Multimesh.Mesh.Duplicate();
if ( ! materials )
{
return;
}
for ( int i = 0; i < numSurfaces; i++ )
{
var m = node.Multimesh.Mesh .SurfaceGetMaterial( i );
node.Multimesh.Mesh.SurfaceSetMaterial( i, (Material)m.Duplicate() );
}
}
}
}

View File

@ -0,0 +1,252 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
namespace Rokojori
{
public class MaterialType
{
public Trillean isStandard = Trillean.Any;
public BaseMaterial3D.TransparencyEnum transparency;
public BaseMaterial3D.BlendModeEnum blendMode;
public BaseMaterial3D.CullModeEnum cullMode;
public BaseMaterial3D.DepthDrawModeEnum depthDrawMode;
public bool noDepthTest = false;
public BaseMaterial3D.ShadingModeEnum shadingMode;
public BaseMaterial3D.DiffuseModeEnum diffuseMode;
public BaseMaterial3D.SpecularModeEnum specularMode;
public bool disableAmbientLight = false;
public bool disableFog = false;
public bool Equals( MaterialType materialType )
{
if ( isStandard != materialType.isStandard )
{
return false;
}
if ( transparency != materialType.transparency )
{
return false;
}
if ( blendMode != materialType.blendMode )
{
return false;
}
if ( cullMode != materialType.cullMode )
{
return false;
}
if ( depthDrawMode != materialType.depthDrawMode )
{
return false;
}
if ( noDepthTest != materialType.noDepthTest )
{
return false;
}
if ( shadingMode != materialType.shadingMode )
{
return false;
}
if ( diffuseMode != materialType.diffuseMode )
{
return false;
}
if ( specularMode != materialType.specularMode )
{
return false;
}
if ( disableAmbientLight != materialType.disableAmbientLight )
{
return false;
}
if ( disableFog != materialType.disableFog )
{
return false;
}
return true;
}
public bool EqualsTo( Material materialType )
{
if ( materialType is StandardMaterial3D sm )
{
return EqualsTo( sm );
}
return false;
}
public bool EqualsTo( StandardMaterial3D materialType )
{
if ( ! TrilleanLogic.Matches( isStandard, true ) )
{
return false;
}
if ( transparency != materialType.Transparency )
{
return false;
}
if ( blendMode != materialType.BlendMode )
{
return false;
}
if ( cullMode != materialType.CullMode )
{
return false;
}
if ( depthDrawMode != materialType.DepthDrawMode )
{
return false;
}
if ( noDepthTest != materialType.NoDepthTest )
{
return false;
}
if ( shadingMode != materialType.ShadingMode )
{
return false;
}
if ( diffuseMode != materialType.DiffuseMode )
{
return false;
}
if ( specularMode != materialType.SpecularMode )
{
return false;
}
if ( disableAmbientLight != materialType.DisableAmbientLight )
{
return false;
}
if ( disableFog != materialType.DisableFog )
{
return false;
}
return true;
}
public void CopyFrom( MaterialType materialType )
{
isStandard = materialType.isStandard;
transparency = materialType.transparency;
blendMode = materialType.blendMode;
cullMode = materialType.cullMode;
depthDrawMode = materialType.depthDrawMode;
noDepthTest = materialType.noDepthTest;
shadingMode = materialType.shadingMode;
diffuseMode = materialType.diffuseMode;
specularMode = materialType.specularMode;
disableAmbientLight = materialType.disableAmbientLight;
disableFog = materialType.disableFog;
}
public override string ToString()
{
return JSON.StringifyObject( this );
}
public static MaterialType From( Material material )
{
if ( material is StandardMaterial3D sm )
{
return From( sm );
}
return null;
}
public static MaterialType From( StandardMaterial3D standardMaterial3D )
{
var mt = new MaterialType();
mt.isStandard = Trillean.True;
// public (?:\w+\.)?\w+ (\w+).*?;
// mt.$1 = standardMaterial3D.$1;
mt.transparency = standardMaterial3D.Transparency;
mt.blendMode = standardMaterial3D.BlendMode;
mt.cullMode = standardMaterial3D.CullMode;
mt.depthDrawMode = standardMaterial3D.DepthDrawMode;
mt.noDepthTest = standardMaterial3D.NoDepthTest;
mt.shadingMode = standardMaterial3D.ShadingMode;
mt.diffuseMode = standardMaterial3D.DiffuseMode;
mt.specularMode = standardMaterial3D.SpecularMode;
mt.disableAmbientLight = standardMaterial3D.DisableAmbientLight;
mt.disableFog = standardMaterial3D.DisableFog;
return mt;
}
public static MaterialType From( MaterialType materialType )
{
var mt = new MaterialType();
mt.isStandard = materialType.isStandard;
mt.transparency = materialType.transparency;
mt.blendMode = materialType.blendMode;
mt.cullMode = materialType.cullMode;
mt.depthDrawMode = materialType.depthDrawMode;
mt.noDepthTest = materialType.noDepthTest;
mt.shadingMode = materialType.shadingMode;
mt.diffuseMode = materialType.diffuseMode;
mt.specularMode = materialType.specularMode;
mt.disableAmbientLight = materialType.disableAmbientLight;
mt.disableFog = materialType.disableFog;
return mt;
}
public void ApplyTo( StandardMaterial3D standardMaterial3D )
{
standardMaterial3D.Transparency = transparency;
standardMaterial3D.BlendMode = blendMode;
standardMaterial3D.CullMode = cullMode;
standardMaterial3D.DepthDrawMode = depthDrawMode;
standardMaterial3D.NoDepthTest = noDepthTest;
standardMaterial3D.ShadingMode = shadingMode;
standardMaterial3D.DiffuseMode = diffuseMode;
standardMaterial3D.SpecularMode = specularMode;
standardMaterial3D.DisableAmbientLight = disableAmbientLight;
standardMaterial3D.DisableFog = disableFog;
}
}
}

View File

@ -0,0 +1 @@
uid://bsiasb06vmuw2

View File

@ -2,8 +2,9 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Godot; using Godot;
using System; using System;
using System.Linq;
using System.Threading.Tasks;
namespace Rokojori namespace Rokojori
{ {
@ -36,6 +37,9 @@ namespace Rokojori
[ExportGroup( "Material")] [ExportGroup( "Material")]
[Export] [Export]
public bool combineMaterials = true; public bool combineMaterials = true;
[Export]
public bool combineORM = true;
public enum TextureSizeMode public enum TextureSizeMode
{ {
@ -53,6 +57,10 @@ namespace Rokojori
[ExportGroup( "Output")] [ExportGroup( "Output")]
[Export] [Export]
public MeshInstance3D outputMesh; public MeshInstance3D outputMesh;
[Export]
public Node3D outputContainer;
[Export] [Export]
public Material[] outputMaterials = []; public Material[] outputMaterials = [];
@ -73,23 +81,57 @@ namespace Rokojori
return _meshGeometryCache[ surface.mesh ][ surface.index ]; return _meshGeometryCache[ surface.mesh ][ surface.index ];
} }
List<Transformable<MeshSurface>> _surfaces; List<Transformable<MeshSurface>> _surfaces = new List<Transformable<MeshSurface>>();
List<Material> _materials; List<Material> _materials = new List<Material>();
MapList<Material,Transformable<MeshSurface>> _materiaList = new MapList<Material, Transformable<MeshSurface>>() ; MapList<Material,Transformable<MeshSurface>> _materiaList = new MapList<Material, Transformable<MeshSurface>>() ;
Dictionary<Material,Transform2D> _uvTransform = new Dictionary<Material, Transform2D>(); Dictionary<Material,Transform2D> _uvTransform = new Dictionary<Material, Transform2D>();
MapList<MaterialType,Material> _materialTypeGroups = new MapList<MaterialType, Material>();
Dictionary<Material,Material> _combinedMaterials = new Dictionary<Material, Material>();
void Clear()
public void Combine()
{ {
GrabSurfaces(); _surfaces.Clear();
GrabMaterials(); _materials.Clear();
_materiaList.Clear();
CombineMaterials(); _uvTransform.Clear();
CombineMeshes(); _materialTypeGroups.Clear();
_combinedMaterials.Clear();
outputMesh = null;
} }
void GrabSurfaces() public async Task Combine()
{ {
Clear();
try
{
await GrabSurfaces();
await GrabMaterials();
await CombineMaterials();
if ( combineMeshes )
{
await CombineMeshes();
}
else
{
await ReassignMaterials();
}
}
catch ( System.Exception e )
{
this.LogError( e );
}
return;
}
async Task GrabSurfaces()
{
_surfaces = new List<Transformable<MeshSurface>>(); _surfaces = new List<Transformable<MeshSurface>>();
foreach ( var n in sourceNodes ) foreach ( var n in sourceNodes )
@ -98,7 +140,7 @@ namespace Rokojori
} }
} }
void GrabMaterials() async Task GrabMaterials()
{ {
_materials = new List<Material>(); _materials = new List<Material>();
_materiaList = new MapList<Material, Transformable<MeshSurface>>(); _materiaList = new MapList<Material, Transformable<MeshSurface>>();
@ -124,18 +166,229 @@ namespace Rokojori
} }
void CombineMaterials() async Task CombineMaterials()
{ {
_materials.ForEach(
m =>
{
var type = _materialTypeGroups.FindKey( k => k.EqualsTo( m ) );
if ( type == null )
{
type = MaterialType.From( m );
}
if ( type == null )
{
return;
}
_materialTypeGroups.Add( type, m );
}
);
this.LogInfo( "Found Groups:", _materialTypeGroups.Count );
foreach ( var gm in _materialTypeGroups )
{
this.LogInfo( "Group:", gm.Key, ">>", gm.Value.Count );
if ( gm.Value.Count > 1 )
{
await CombineStandardMaterials( gm.Value );
}
}
} }
void CombineMeshes() async Task<StandardMaterial3D> CombineStandardMaterials( List<Material> anyMaterials )
{
var materials = Lists.FilterType<Material,StandardMaterial3D>( anyMaterials );
var outputMaterial = (StandardMaterial3D) materials[ 0 ].Duplicate();
var alignment = TextureMerger.ComputeTextureAlignment( anyMaterials.Count );
for ( int i = 0; i < materials.Count; i++ )
{
var box = TextureMerger.GetUVAlignmentBoxFor( alignment, i );
var transform = Transform2D.Identity;
transform = transform.ScaledLocal( box.size );
transform.Origin = box.min;
_uvTransform[ materials[ i ] ] = transform;
_combinedMaterials[ materials[ i ] ] = outputMaterial;
this.LogInfo( "Set UV transform:", i, box.min, box.size.Inverse() );
}
var textureTypes = new List<string>
{
"albedo",
"metallic",
"roughness",
"emission",
"normal",
"rim",
"clearcoat",
"anisotropy_flowmap",
"ao",
"height",
"subsurf_scatter",
"backlight",
"refraction"
};
var hasAlebdoAlpha = true;
var mm = new StandardMaterial3D();
foreach ( var t in textureTypes )
{
if ( combineORM && ( t == "roughness" || t == "metallic" ) )
{
continue;
}
var hasAlpha = hasAlebdoAlpha && t == "albedo";
var name = Texture2DPropertyName.Create( t + "_texture" );
var textures = Lists.Map( materials, m => name.Get( m ) );
var noTextures = textures.Find( t => t != null ) == null;
if ( noTextures )
{
continue;
}
var fallBackColors = Lists.Map(
textures, i =>
{
if ( t == "ao" && combineORM )
{
return new Color( 1, 1, 0 );
}
if ( t == "albedo" )
{
return new Color( 1, 1, 1 );
}
if ( t == "normal" )
{
return new Color( 0.5f, 0.5f, 1 );
}
return new Color( 0, 0, 0 );
}
);
var textureSize = new Vector2( 512, 512 );
if ( TextureSizeMode.Custom == textureSizeMode )
{
textureSize = customTextureSize;
}
else if ( TextureSizeMode.KeepOriginal == textureSizeMode )
{
textures.ForEach(
t =>
{
if ( t == null )
{
return;
}
textureSize.X = Mathf.Max( t.GetWidth(),textureSize.X );
textureSize.Y = Mathf.Max( t.GetWidth(),textureSize.Y );
}
);
this.LogInfo( "Computing next power of two texture Size", textureSize, alignment );
textureSize.X = MathX.NextPowerOfTwo( textureSize.X * alignment.X );
textureSize.Y = MathX.NextPowerOfTwo( textureSize.Y * alignment.Y );
}
this.LogInfo( "Texture Size", t, ">>", textures.Count, textureSize, alignment );
var texture = TextureCombinerBuffer.GridMerge(
(int) textureSize.X, (int)textureSize.Y,
new Color( 1, 0, 0, hasAlpha ? 0 : 1 ),
hasAlpha, true, alignment,
textures, fallBackColors
);
this.LogInfo( "Combined textures:", t );
name.Set( outputMaterial, texture );
await this.RequestNextFrame();
}
return outputMaterial;
}
async Task ReassignMaterials()
{
if ( outputContainer == null )
{
outputContainer = this.CreateChild<Node3D>();
}
outputContainer.DestroyChildren();
foreach ( var n in sourceNodes )
{
var root = n.DeepCopyTo( outputContainer );
var materialContainers = MeshExtractor.ExtractMaterialContainersInHierarchy( root, null, true );
materialContainers.ForEach(
mc =>
{
mc.MakeUnique( false );
mc.ForAllSurfaces(
( surface )=>
{
var slot = surface.GetActiveMaterialSlot();
if ( MaterialSurfaceContainer.MaterialSlot.None == slot )
{
return;
}
var material = surface.GetActiveMaterial();
if ( _combinedMaterials.ContainsKey( material ) )
{
surface.SetActiveMaterial( _combinedMaterials[ material ] );
}
}
);
}
);
}
}
async Task CombineMeshes()
{ {
var arrayMesh = new ArrayMesh(); var arrayMesh = new ArrayMesh();
this.LogInfo( "Combining", _surfaces.Count, "meshes" ); this.LogInfo( "Combining", _surfaces.Count, "meshes" );
var index = 0; var index = 0;
var combined = new MapList<Material,MeshGeometry>();
var outputMaterials = new List<Material>();
_materials.ForEach( _materials.ForEach(
( m )=> ( m )=>
@ -155,6 +408,7 @@ namespace Rokojori
if ( uvTransform != null ) if ( uvTransform != null )
{ {
this.LogInfo( "Appling uvTransform:", uvTransform );
smg.ApplyUVTransform( (Transform2D) uvTransform ); smg.ApplyUVTransform( (Transform2D) uvTransform );
} }
@ -171,22 +425,61 @@ namespace Rokojori
} }
); );
var isCombinedMaterial = _combinedMaterials.ContainsKey( m );
if ( isCombinedMaterial )
{
this.LogInfo( "Add material groups", m );
combined.Add( _combinedMaterials[ m ], meshGeometry );
return;
}
meshGeometry.GenerateMesh( Mesh.PrimitiveType.Triangles, arrayMesh ); meshGeometry.GenerateMesh( Mesh.PrimitiveType.Triangles, arrayMesh );
arrayMesh.SurfaceSetMaterial( index, m ); arrayMesh.SurfaceSetMaterial( index, m );
outputMaterials.Add( m );
index ++; index ++;
} }
); );
this.LogInfo( "Combining material groups", combined.Count );
foreach ( var cm in combined )
{
var material = cm.Key;
var meshes = cm.Value;
this.LogInfo( "Combining meshes", meshes.Count);
var combinedMG = MeshGeometry.Combine( meshes );
this.LogInfo( "Combed meshes, num tris:", combinedMG.numTriangles );
combinedMG.GenerateMesh( Mesh.PrimitiveType.Triangles, arrayMesh );
this.LogInfo( "Add surface", index);
arrayMesh.SurfaceSetMaterial( index, material );
this.LogInfo( "Add material", material );
outputMaterials.Add( material );
this.LogInfo( "Increment index" );
index ++;
}
this.LogInfo( "Processing done, adding outputs", arrayMesh.GetSurfaceCount() );
if ( outputMesh == null ) if ( outputMesh == null )
{ {
this.LogInfo( "Created outputMesh");
outputMesh = this.CreateChild<MeshInstance3D>(); outputMesh = this.CreateChild<MeshInstance3D>();
} }
outputMesh.Mesh = arrayMesh;
outputMaterials = _materials.ToArray(); this.outputMaterials = outputMaterials.ToArray();
outputMesh.Mesh = arrayMesh;
return;
} }

View File

@ -9,6 +9,62 @@ namespace Rokojori
{ {
public class MeshExtractor public class MeshExtractor
{ {
public static List<MaterialSurfaceContainer> ExtractMaterialContainersInHierarchy( Node n, List<MaterialSurfaceContainer> list = null, bool ownersOnly = false )
{
list = list == null ? new List<MaterialSurfaceContainer>() : list;
Nodes.ForEach<Node3D>( n,
n =>
{
ExtractMaterialContainers( n, list, ownersOnly );
}
);
return list;
}
public static List<MaterialSurfaceContainer> ExtractMaterialContainers( Node n, List<MaterialSurfaceContainer> list = null, bool ownersOnly = false )
{
list = list == null ? new List<MaterialSurfaceContainer>() : list;
if ( n is MeshInstance3D mi && mi.Mesh != null )
{
if ( ! ownersOnly )
{
for ( int i = 0; i < mi.Mesh.GetSurfaceCount(); i++ )
{
list.Add( new MeshSurfaceContainer( mi, i ) );
}
}
else
{
list.Add( new MeshSurfaceContainer( mi, -1 ) );
}
}
if ( n is MultiMeshInstance3D mmi && mmi.Multimesh != null && mmi.Multimesh.Mesh != null )
{
if ( ! ownersOnly )
{
for ( int i = 0; i < mmi.Multimesh.Mesh.GetSurfaceCount(); i++ )
{
list.Add( new MultiMeshSurfaceContainer( mmi, i ) );
}
}
else
{
list.Add( new MultiMeshSurfaceContainer( mmi, -1 ) );
}
}
return list;
}
public static bool CanExtract( Node3D n ) public static bool CanExtract( Node3D n )
{ {
if ( n is MeshInstance3D mi ) if ( n is MeshInstance3D mi )
@ -102,18 +158,20 @@ namespace Rokojori
return list; return list;
} }
public static List<Transformable<MeshSurface>> ExtractSurfaces( Node n, List<Transformable<MeshSurface>> list = null ) public static List<Transformable<MeshSurface>> ExtractSurfaces( Node n, List<Transformable<MeshSurface>> list = null, bool trackOwners = false )
{ {
list = list == null ? new List<Transformable<MeshSurface>>() : list; list = list == null ? new List<Transformable<MeshSurface>>() : list;
if ( n is MeshInstance3D mi ) if ( n is MeshInstance3D mi )
{ {
var owner = trackOwners ? mi : null;
var mesh = mi.Mesh; var mesh = mi.Mesh;
for ( int i = 0; i < mesh.GetSurfaceCount(); i++ ) for ( int i = 0; i < mesh.GetSurfaceCount(); i++ )
{ {
var surface = new MeshSurface( mesh, mesh.SurfaceGetMaterial( i ), i ); var surface = new MeshSurface( mesh, mesh.SurfaceGetMaterial( i ), i, owner );
if ( i < mi.GetSurfaceOverrideMaterialCount() && mi.GetSurfaceOverrideMaterial( i ) != null ) if ( i < mi.GetSurfaceOverrideMaterialCount() && mi.GetSurfaceOverrideMaterial( i ) != null )
{ {
@ -131,6 +189,7 @@ namespace Rokojori
if ( n is MultiMeshInstance3D mmi ) if ( n is MultiMeshInstance3D mmi )
{ {
var owner = trackOwners ? mmi : null;
var mm = mmi.Multimesh; var mm = mmi.Multimesh;
for ( var j = 0; j < mm.InstanceCount; j++ ) for ( var j = 0; j < mm.InstanceCount; j++ )
@ -140,7 +199,7 @@ namespace Rokojori
for ( int i = 0; i < mesh.GetSurfaceCount(); i++ ) for ( int i = 0; i < mesh.GetSurfaceCount(); i++ )
{ {
var surface = new MeshSurface( mesh, mesh.SurfaceGetMaterial( i ), i ); var surface = new MeshSurface( mesh, mesh.SurfaceGetMaterial( i ), i, mmi, j );
if ( mmi.MaterialOverride != null ) if ( mmi.MaterialOverride != null )
{ {

View File

@ -437,7 +437,14 @@ namespace Rokojori
{ {
this.name = name; this.name = name;
Initialize( normals, uvs, colors, uvs2 ); Initialize( normals, uvs, colors, uvs2 );
} }
public static MeshGeometry Combine( List<MeshGeometry> meshes )
{
var mg = new MeshGeometry();
meshes.ForEach( m => mg.Add( m ) );
return mg;
}
public static MeshGeometry BillboardQuad( float size = 1 ) public static MeshGeometry BillboardQuad( float size = 1 )
{ {

View File

@ -12,12 +12,16 @@ namespace Rokojori
public Mesh mesh; public Mesh mesh;
public Material material; public Material material;
public int index; public int index;
public Node owner;
public int instanceIndex;
public MeshSurface( Mesh mesh, Material material, int index = 0 ) public MeshSurface( Mesh mesh, Material material, int index, Node owner = null, int instanceIndex = -1 )
{ {
this.index = index; this.index = index;
this.mesh = mesh; this.mesh = mesh;
this.material = material; this.material = material;
this.owner = owner;
this.instanceIndex = instanceIndex;
} }
} }
} }

View File

@ -145,7 +145,7 @@ namespace Rokojori
return divisions; return divisions;
} }
var v = MathX.NextPowerOfTwo( divisions ); var v = MathX.NextPowerOfTwoExponent( divisions );
return v * v; return v * v;
} }

View File

@ -37,6 +37,22 @@ namespace Rokojori
} }
} }
public void Fill( Color color, int x, int y, int w, int h )
{
for ( int i = 0; i < w; i++ )
{
for ( int j = 0; j < h; j++ )
{
SetAt( i + x, j + y, color );
}
}
}
public void Fill( Color color )
{
Fill( color, 0, 0, width, height );
}
public static TextureCombinerBuffer From( Texture2D texture, int srgbConversion = 0 ) public static TextureCombinerBuffer From( Texture2D texture, int srgbConversion = 0 )
{ {
var buffer = Create( texture.GetWidth(), texture.GetHeight() ); var buffer = Create( texture.GetWidth(), texture.GetHeight() );
@ -45,6 +61,79 @@ namespace Rokojori
return buffer; return buffer;
} }
public void CopyFromSampled( TextureCombinerBuffer source, int x, int y, int w, int h )
{
RJLog.Log( "Copy Sampled", x,y, w, h );
for ( int i = 0; i < w; i ++ )
{
for ( int j = 0; j < h; j++ )
{
float u = i / (float)( w );
float v = j / (float)( h );
var sourceX = Mathf.RoundToInt( u * source.width );
var sourceY = Mathf.RoundToInt( v * source.height );
var color = source.GetAt( sourceX, sourceY );
SetAt( x + i, y + j, color );
}
}
}
public static Texture2D GridMerge( int w, int h, Color background, bool alpha, bool mipMaps,
Vector2I alignment,
List<Texture2D> textures, List<Color> nullTextureColors )
{
var positions = new List<Vector2I>();
var sizes = new List<Vector2I>();
var mergeSize = new Vector2( w, h );
var gridSize = (Vector2I)( mergeSize / alignment );
RJLog.Log( "GridMerge" );
for ( int i = 0; i < textures.Count; i++ )
{
var box = TextureMerger.GetUVAlignmentBoxFor( alignment, i );
var position = (Vector2I) ( box.min * mergeSize );
positions.Add( position );
sizes.Add( gridSize );
RJLog.Log( i, position, gridSize );
}
return Merge( w, h, background, alpha, mipMaps, textures, nullTextureColors, positions, sizes );
}
public static Texture2D Merge( int w, int h, Color background, bool alpha, bool mipMaps,
List<Texture2D> textures, List<Color> nullTextureColors, List<Vector2I> positions, List<Vector2I> sizes )
{
var buffer = Create( w, h );
buffer.Fill( background );
for ( int i = 0; i < textures.Count; i++ )
{
var position = positions[ i ];
var size = sizes[ i ];
if ( textures[ i ] == null )
{
buffer.Fill( nullTextureColors[ i ], position.X, position.Y, size.X, size.Y );
continue;
}
var imageBuffer = From( textures[ i ] );
buffer.CopyFromSampled( imageBuffer, position.X, position.Y, size.X, size.Y );
}
return buffer.CreateImageTexture( alpha, mipMaps );
}
public ImageTexture CreateImageTexture( bool alpha = true, bool generateMipmaps = false ) public ImageTexture CreateImageTexture( bool alpha = true, bool generateMipmaps = false )
{ {
var image = Image.CreateEmpty( width, height, generateMipmaps, alpha ? Image.Format.Rgba8 : Image.Format.Rgb8); var image = Image.CreateEmpty( width, height, generateMipmaps, alpha ? Image.Format.Rgba8 : Image.Format.Rgb8);
@ -75,7 +164,7 @@ namespace Rokojori
return buffer; return buffer;
} }
public void CopyFrom( Image image, int sourceX, int sourceY, int ownX, int ownY, int w, int h, int srgbConversion = 0 ) public void CopyFrom( Image image, int sourceX, int sourceY, int ownX, int ownY, int w, int h, int srgbConversion = 0 )
{ {

View File

@ -1,15 +1,18 @@
using Godot; using Godot;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
namespace Rokojori namespace Rokojori
{ {
public partial class RDContext public partial class RDContext
{ {
protected List<RenderingObject> _cleanUps = new List<RenderingObject>(); protected List<RDObject> _cleanUps = new List<RDObject>();
protected List<string> _cleanUpInfo = new List<string>(); protected List<string> _cleanUpInfo = new List<string>();
public void Free( RenderingObject ro, string info = null ) protected bool cleanAll = false;
public void Free( RDObject ro, string info = null )
{ {
if ( ro == null ) if ( ro == null )
{ {
@ -23,27 +26,54 @@ namespace Rokojori
return; return;
} }
if ( ro is RDPipeline ) if ( ! cleanAll && ro is RDPipeline )
{ {
Verbose( "Not cleaning pipelines" ); Verbose( "Not cleaning pipelines" );
return; return;
} }
if ( ro is RDUniformSet ) if ( ! cleanAll && ro is RDUniformSet )
{ {
Verbose( "Not cleaning uniform sets" ); Verbose( "Not cleaning uniform sets" );
return; return;
} }
Verbose( "Cleaning up: ", info, ro.rid ); Verbose( "Cleaning up: ", info, ro.rid );
renderingDevice.FreeRid( ro.rid ); ro.Free( this );
} }
public string GetMemoryInfo()
{
var types = new List<RenderingDevice.MemoryType>(){
RenderingDevice.MemoryType.Buffers,
RenderingDevice.MemoryType.Textures,
RenderingDevice.MemoryType.Total
};
var sb = new StringBuilder();
types.ForEach(
( t ) =>
{
var size = renderingDevice.GetMemoryUsage( t );
var sizeInfo = Bytes.ConvertToString( size );
sb.Append( t + ": " + sizeInfo + "(" + size + " bytes) " );
}
);
// Verbose( "Cleaning up:", renderingDevice.GetMemoryUsage() );
return sb.ToString();
}
public void CleanUp() public void CleanUp()
{ {
var index = 0; var index = 0;
Verbose( "Memory before cleanup");
Verbose( GetMemoryInfo() );
_cleanUps.ForEach( _cleanUps.ForEach(
c => c =>
{ {
@ -52,10 +82,26 @@ namespace Rokojori
} }
); );
Verbose( "Memory after cleanup" );
Verbose( GetMemoryInfo() );
_cleanUps.Clear(); _cleanUps.Clear();
_cleanUpInfo.Clear();
} }
public void AddToCleanUp( RenderingObject ro, string info = null ) public void Free()
{
renderingDevice.Free();
_renderingDevice = null;
}
public void CleanUpAndFree()
{
CleanUp();
Free();
}
public void AddToCleanUp( RDObject ro, string info = null )
{ {
if ( _cleanUps.Contains( ro ) ) if ( _cleanUps.Contains( ro ) )
{ {
@ -66,7 +112,7 @@ namespace Rokojori
_cleanUpInfo.Add( info ); _cleanUpInfo.Add( info );
} }
public void AddToCleanUp( List<RenderingObject> ro, string info = null ) public void AddToCleanUp( List<RDObject> ro, string info = null )
{ {
var index = 0; var index = 0;
info = info == null ? "" : info; info = info == null ? "" : info;

View File

@ -26,6 +26,13 @@ namespace Rokojori
return ctx; return ctx;
} }
public static RDContext Current()
{
var ctx = new RDContext();
ctx.Initialize( false );
return ctx;
}
public void Initialize( bool local = false) public void Initialize( bool local = false)
{ {
_localRenderingDevice = local; _localRenderingDevice = local;

View File

@ -0,0 +1,36 @@
using Godot;
namespace Rokojori
{
public class RDObject
{
protected RDContext _context;
public RDContext context => _context;
protected Rid _rid;
public Rid rid => _rid;
protected bool _isDestroyed = false;
public bool valid => ! _isDestroyed && _context != null && _rid.IsValid;
public RDObject( RDContext context, Rid rid )
{
_context = context;
_rid = rid;
_context.AddToCleanUp( this, GetType().Name + "@" + _rid );
context.Verbose( "Creating", GetType().Name, rid );
}
public void Free( RDContext context )
{
context.renderingDevice.FreeRid( _rid );
_rid = new Rid();
_context = null;
_isDestroyed = true;
}
}
}

View File

@ -0,0 +1 @@
uid://0oqflnt3k5lr

View File

@ -3,7 +3,7 @@ using Godot;
namespace Rokojori namespace Rokojori
{ {
public class RDPipeline: RenderingObject public class RDPipeline: RDObject
{ {
public RDPipeline( RDContext context, Rid rid ):base( context, rid ) public RDPipeline( RDContext context, Rid rid ):base( context, rid )
{} {}

View File

@ -3,7 +3,7 @@ using Godot;
namespace Rokojori namespace Rokojori
{ {
public class RDSampler: RenderingObject public class RDSampler: RDObject
{ {
public RDSampler( RDContext effect, Rid rid ):base( effect, rid ) public RDSampler( RDContext effect, Rid rid ):base( effect, rid )
{} {}

View File

@ -3,7 +3,7 @@ using Godot;
namespace Rokojori namespace Rokojori
{ {
public class RDShader: RenderingObject public class RDShader: RDObject
{ {
public RDShader( RDContext context, Rid rid ):base( context, rid ) public RDShader( RDContext context, Rid rid ):base( context, rid )
{} {}

View File

@ -3,7 +3,7 @@ using Godot;
namespace Rokojori namespace Rokojori
{ {
public class RDTexture: RenderingObject public class RDTexture: RDObject
{ {
public RDTexture( RDContext context, Rid rid ):base( context, rid ){} public RDTexture( RDContext context, Rid rid ):base( context, rid ){}

View File

@ -187,7 +187,7 @@ namespace Rokojori
public static RenderingDevice.DataFormat ImageFormatToDataFormat( Image.Format imageFormat ) public static RenderingDevice.DataFormat ImageFormatToDataFormat( Image.Format imageFormat )
{ {
RJLog.Log( "ImageFormatToDataFormat", imageFormat ); // RJLog.Log( "ImageFormatToDataFormat", imageFormat );
switch ( imageFormat ) switch ( imageFormat )
{ {

View File

@ -4,7 +4,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
public class RDUniformSet:RenderingObject public class RDUniformSet:RDObject
{ {
protected int _setIndex = -1; protected int _setIndex = -1;
public int setIndex => _setIndex; public int setIndex => _setIndex;

View File

@ -1,27 +0,0 @@
using Godot;
namespace Rokojori
{
public class RenderingObject
{
protected RDContext _context;
public RDContext context => _context;
protected Rid _rid;
public Rid rid => _rid;
public bool valid => _rid.IsValid;
public RenderingObject( RDContext context, Rid rid )
{
this._context = context;
this._rid = rid;
this._context.AddToCleanUp( this, GetType().Name + "@" + _rid );
context.Verbose( "Creating", GetType().Name, rid );
}
}
}

View File

@ -6,13 +6,7 @@ vec3 applyMatrix( vec3 v, mat4 m )
vec3 applyMatrixWithoutTranslation( vec3 v, mat4 m ) vec3 applyMatrixWithoutTranslation( vec3 v, mat4 m )
{ {
mat4 mw = m; return ( m * vec4( v, 0.0 ) ).xyz;
mw[ 3 ][ 0 ] = 0.0;
mw[ 3 ][ 1 ] = 0.0;
mw[ 3 ][ 2 ] = 0.0;
mw[ 3 ][ 3 ] = 1.0;
return ( mw * vec4( v, 1.0 ) ).xyz;
} }
vec3 applyMatrix( vec3 v, mat3 m ) vec3 applyMatrix( vec3 v, mat3 m )
@ -20,35 +14,20 @@ vec3 applyMatrix( vec3 v, mat3 m )
return ( m * v ).xyz; return ( m * v ).xyz;
} }
// L W V
// L
// W
// V
// LD WD VD
// LD
// WD
// VD
vec3 localToWorld( vec3 local, mat4 _MODEL_MATRIX ) vec3 localToWorld( vec3 local, mat4 _MODEL_MATRIX )
{ {
return ( _MODEL_MATRIX * vec4( local, 1.0 ) ).xyz; return applyMatrix( local, _MODEL_MATRIX );
} }
vec3 localToWorldDirection( vec3 local, mat4 _MODEL_MATRIX ) vec3 localToWorldDirection( vec3 local, mat4 _MODEL_MATRIX )
{ {
mat4 mw = _MODEL_MATRIX; return applyMatrixWithoutTranslation( local, _MODEL_MATRIX );
mw[ 3 ][ 0 ] = 0.0;
mw[ 3 ][ 1 ] = 0.0;
mw[ 3 ][ 2 ] = 0.0;
mw[ 3 ][ 3 ] = 1.0;
return ( mw * vec4( local, 1.0 ) ).xyz;
} }
vec3 localToView( vec3 local, mat4 _MODELVIEW_MATRIX ) vec3 localToView( vec3 local, mat4 _MODELVIEW_MATRIX )
{ {
return ( _MODELVIEW_MATRIX * vec4( local, 1.0 ) ).xyz; return applyMatrix( local, _MODELVIEW_MATRIX );
} }
vec3 localToViewDirection( vec3 local, mat4 _MODELVIEW_MATRIX ) vec3 localToViewDirection( vec3 local, mat4 _MODELVIEW_MATRIX )
@ -63,35 +42,25 @@ vec3 localToViewDirection( vec3 local, mat3 _MODELVIEW_NORMAL_MATRIX )
vec3 worldToLocal( vec3 world, mat4 _MODEL_MATRIX ) vec3 worldToLocal( vec3 world, mat4 _MODEL_MATRIX )
{ {
return ( inverse( _MODEL_MATRIX ) * vec4( world, 1.0 ) ).xyz; mat4 inversedMatrix = inverse( _MODEL_MATRIX );
return applyMatrix( world, inv );
} }
vec3 worldToLocalDirection( vec3 world, mat4 _MODEL_MATRIX ) vec3 worldToLocalDirection( vec3 world, mat4 _MODEL_MATRIX )
{ {
mat4 mw = inverse( _MODEL_MATRIX ); mat4 inversedMatrix = inverse( _MODEL_MATRIX );
mw[ 3 ][ 0 ] = 0.0; return applyMatrixWithoutTranslation( world, inversedMatrix );
mw[ 3 ][ 1 ] = 0.0;
mw[ 3 ][ 2 ] = 0.0;
mw[ 3 ][ 3 ] = 1.0;
return ( mw * vec4( world, 1.0 ) ).xyz;
} }
vec3 worldToView( vec3 world, mat4 _VIEW_MATRIX ) vec3 worldToView( vec3 world, mat4 _VIEW_MATRIX )
{ {
return ( _VIEW_MATRIX * vec4( world, 1.0 ) ).xyz; return applyMatrix( world, _VIEW_MATRIX );
} }
vec3 worldToViewDirection( vec3 worldDirection, mat4 _VIEW_MATRIX ) vec3 worldToViewDirection( vec3 worldDirection, mat4 _VIEW_MATRIX )
{ {
mat4 mw = _VIEW_MATRIX; return applyMatrixWithoutTranslation( worldDirection, _VIEW_MATRIX );
mw[ 3 ][ 0 ] = 0.0;
mw[ 3 ][ 1 ] = 0.0;
mw[ 3 ][ 2 ] = 0.0;
mw[ 3 ][ 3 ] = 1.0;
return ( mw * vec4( worldDirection, 1.0 ) ).xyz;
} }
vec3 viewToWorld( vec3 view, mat4 _INV_VIEW_MATRIX ) vec3 viewToWorld( vec3 view, mat4 _INV_VIEW_MATRIX )
@ -101,14 +70,7 @@ vec3 viewToWorld( vec3 view, mat4 _INV_VIEW_MATRIX )
vec3 viewToWorldDirection( vec3 viewDirection, mat4 _INV_VIEW_MATRIX ) vec3 viewToWorldDirection( vec3 viewDirection, mat4 _INV_VIEW_MATRIX )
{ {
mat4 mw = _INV_VIEW_MATRIX; return applyMatrixWithoutTranslation( viewDirection, _INV_VIEW_MATRIX );
mw[ 3 ][ 0 ] = 0.0;
mw[ 3 ][ 1 ] = 0.0;
mw[ 3 ][ 2 ] = 0.0;
mw[ 3 ][ 3 ] = 1.0;
return applyMatrix( viewDirection, mw );
} }
vec3 viewToLocal( vec3 view, mat4 _INV_VIEW_MATRIX, mat4 _MODEL_MATRIX ) vec3 viewToLocal( vec3 view, mat4 _INV_VIEW_MATRIX, mat4 _MODEL_MATRIX )

View File

@ -63,7 +63,7 @@ namespace Rokojori
var value = p.GetValue( material ); var value = p.GetValue( material );
RJLog.Log( "GetStandardValue", _cSharpName, p.Name, ">>", value ); // RJLog.Log( "GetStandardValue", _cSharpName, p.Name, ">>", value );
return (T) p.GetValue( material ); return (T) p.GetValue( material );
} }
@ -82,6 +82,12 @@ namespace Rokojori
if ( ! RegexUtility.StartsWithUpperCase( propertyName ) ) if ( ! RegexUtility.StartsWithUpperCase( propertyName ) )
{ {
_cSharpName = GDScriptNames.ToCS( propertyName ); _cSharpName = GDScriptNames.ToCS( propertyName );
if ( propertyName.StartsWith( "ao" ) )
{
_cSharpName = _cSharpName[ 0 ] + ( _cSharpName[ 1 ] + "" ).ToUpper() + _cSharpName.Substring( 2 );
}
} }
else else
{ {
@ -89,7 +95,7 @@ namespace Rokojori
} }
var p = type.GetProperty( _cSharpName ); var p = type.GetProperty( _cSharpName );
RJLog.Log( "_cSharpName", _cSharpName, material ); // RJLog.Log( "_cSharpName", _cSharpName, material );
_propertyInfoCache.Set( type, _cSharpName, p ); _propertyInfoCache.Set( type, _cSharpName, p );
return _propertyInfoCache[ type ][ _cSharpName ]; return _propertyInfoCache[ type ][ _cSharpName ];

View File

@ -17,6 +17,21 @@ namespace Rokojori
callback( kv.Key, kv.Value ); callback( kv.Key, kv.Value );
} }
} }
public K FindKey( Func<K, bool> evaluater )
{
foreach ( var kv in this )
{
if ( evaluater( kv.Key ) )
{
return kv.Key;
}
}
return default( K );
}
} }
public class StringMap : Map<string,string> public class StringMap : Map<string,string>

View File

@ -295,7 +295,17 @@ namespace Rokojori
} }
else if ( value is Enum ) else if ( value is Enum )
{ {
jsonObject.Set( name, (int) value ); var size = ReflectionHelper.GetEnumSizeInBits( value.GetType() );
if ( size == 32 )
{
jsonObject.Set( name, (int) value );
}
else if ( size == 64 )
{
jsonObject.Set( name, (long) value );
}
} }
else if ( ReflectionHelper.IsList( value ) ) else if ( ReflectionHelper.IsList( value ) )
{ {

View File

@ -8,6 +8,35 @@ namespace Rokojori
{ {
public class ReflectionHelper public class ReflectionHelper
{ {
public static T Create<T>( Type type, params object[] args )
{
Type[] argTypes = Array.ConvertAll( args, arg => arg.GetType() );
var constructorMethod = type.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, argTypes, null
);
if ( constructorMethod == null )
{
return default(T);
}
return (T)constructorMethod.Invoke( args );
}
public static int GetEnumSizeInBits( Type enumType )
{
if ( ! enumType.IsEnum )
{
return -1;
}
var underlyingType = Enum.GetUnderlyingType( enumType );
return System.Runtime.InteropServices.Marshal.SizeOf( underlyingType ) * 8;
}
public static Type GetTypeByNameFromAssembly( string name, Assembly assembly ) public static Type GetTypeByNameFromAssembly( string name, Assembly assembly )
{ {
var type = assembly.GetType( name ); var type = assembly.GetType( name );