Transform/Grass Udpate

This commit is contained in:
Josef 2025-05-14 14:31:32 +02:00
parent 4f496cc7cc
commit 7de06b4bcd
26 changed files with 879 additions and 126 deletions

View File

@ -226,6 +226,18 @@ namespace Rokojori
return CreateChildIn<T>( parent, name ); return CreateChildIn<T>( parent, name );
} }
public static T GetOrCreateChild<T>( this Node parent, string name = null ) where T:Node,new()
{
var child = Nodes.GetDirectChild<T>( parent );
if ( child == null )
{
child = parent.CreateChild<T>( name );
}
return child;
}
public static T CreateChildLocal3D<T>( this Node parent, Vector3 position, Quaternion? rotation, string name = null ) where T:Node3D,new() public static T CreateChildLocal3D<T>( this Node parent, Vector3 position, Quaternion? rotation, string name = null ) where T:Node3D,new()
{ {
var c = CreateChildIn<T>( parent, name ); var c = CreateChildIn<T>( parent, name );

View File

@ -78,6 +78,11 @@ namespace Rokojori
return new Vector3( v.X, 0, v.Y ); return new Vector3( v.X, 0, v.Y );
} }
public static Vector3 XY( Vector2 v )
{
return new Vector3( v.X, v.Y, 0.0f );
}
public static float Dot( Vector3 a, Vector3 b ) public static float Dot( Vector3 a, Vector3 b )
{ {
return a.Dot( b ); return a.Dot( b );
@ -485,8 +490,27 @@ namespace Rokojori
} }
node.LookAt( forward + node.GlobalPosition, up ); node.LookAt( forward + node.GlobalPosition, up );
}
public static bool IsZero( this Quaternion q )
{
return q.X == 0 && q.Y == 0 && q.Z == 0 && q.W == 0;
} }
public static bool IsValid( this Quaternion q )
{
return ! ( q.IsFinite() || q.IsZero() );
}
public static Quaternion GetNormalized( this Quaternion q )
{
if ( q.IsValid() )
{
return Quaternion.Identity;
}
return q.Normalized();
}
public static Quaternion GetDifference( this Quaternion q, Quaternion other ) public static Quaternion GetDifference( this Quaternion q, Quaternion other )
{ {

View File

@ -13,6 +13,11 @@ namespace Rokojori
[Export] [Export]
public float yawOffset = 0; public float yawOffset = 0;
[Export]
public MeshAxisSubDivider uSubDivisions;
[Export]
public MeshAxisSubDivider vSubDivisions;
public override int GetNumViews() public override int GetNumViews()
{ {
return useDoubleSidedMaterial ? 1 : 2; return useDoubleSidedMaterial ? 1 : 2;
@ -44,6 +49,7 @@ namespace Rokojori
var angle = yawOffset; var angle = yawOffset;
for ( int i = 0; i < numTextures; i++ ) for ( int i = 0; i < numTextures; i++ )
{ {
@ -52,10 +58,17 @@ namespace Rokojori
bakerCameras[ index ].viewSettings.yaw = angle + i * 180f; bakerCameras[ index ].viewSettings.yaw = angle + i * 180f;
bakerCameras[ index ].viewSettings.pitch = 0; bakerCameras[ index ].viewSettings.pitch = 0;
var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true ); var uv = TextureMerger.GetUVRectangle( textureAlignment, index, true );
var q = new MeshGeometry(); var q = new MeshGeometry();
q.AddQuad( bakerCameras[ index ].viewSettings.bakingRotation, outputScale, uv.min, uv.max ); var transform3D = Math3D.TRS( Vector3.Zero, bakerCameras[ index ].viewSettings.bakingRotation, Vector3.One * outputScale );
var uDivisions = MeshAxisSubDivider.GetSubDivisionsU( uSubDivisions, transform3D );
var vDivisions = MeshAxisSubDivider.GetSubDivisionsV( vSubDivisions, transform3D );
q.AddQuadWithCustomDivisions( bakerCameras[ index ].viewSettings.bakingRotation, outputScale, uv.min, uv.max, uDivisions, vDivisions );
mg.Add( q ); mg.Add( q );

View File

@ -0,0 +1,30 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
using System.Linq;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class GridSubDivider:MeshAxisSubDivider
{
[Export]
public int numSubDivisions = 1;
public override List<float> GetSubDivisions( Transform3D quadTransform, Axis axis )
{
var list = new List<float>();
for ( int i = 0; i < numSubDivisions; i++ )
{
float s = (float)( i + 1f ) / (float)( numSubDivisions + 1f );
}
return list;
}
}
}

View File

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

View File

@ -0,0 +1,64 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
using System.Linq;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class ManualAbsoluteSubDivider:MeshAxisSubDivider
{
public enum SourceAxis
{
X,
Y,
Z
}
[Export]
public SourceAxis sourceAxis;
[Export]
public float[] subDivisions;
public override List<float> GetSubDivisions( Transform3D quadTransform, Axis axis )
{
var min = GetWorldMin( quadTransform );
var max = GetWorldMax( quadTransform );
var minV = min.X;
var maxV = max.X;
if ( SourceAxis.Y == sourceAxis )
{
minV = min.Y;
maxV = max.Y;
}
if ( SourceAxis.Z == sourceAxis )
{
minV = min.Z;
maxV = max.Z;
}
var list = new List<float>();
for ( int i = 0; i < subDivisions.Length; i++ )
{
var mapped = MathX.Normalize( list[ i ], minV, maxV );
if ( mapped <= 0 || mapped >= 1 )
{
continue;
}
list.Add( mapped );
}
return list;
}
}
}

View File

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

View File

@ -0,0 +1,23 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
using System.Linq;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class ManualRelativeSubDivider:MeshAxisSubDivider
{
[Export]
public float[] subDivisions;
public override List<float> GetSubDivisions( Transform3D quadTransform, Axis axis )
{
return Lists.From( subDivisions );
}
}
}

View File

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

View File

@ -0,0 +1,65 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
using System.Linq;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class MeshAxisSubDivider:Resource
{
public enum Axis
{
U,
V
}
public virtual List<float> GetSubDivisions( Transform3D quadTransform, Axis axis )
{
return new List<float>();
}
public Vector3 GetWorldMin( Transform3D worldTransform )
{
return worldTransform * new Vector3( -0.5f, -0.5f, 0.0f);
}
public Vector3 GetWorldMax( Transform3D worldTransform )
{
return worldTransform * new Vector3( 0.5f, 0.5f, 0.0f);
}
public Vector3 AxisToVector( Axis a, float t = 1)
{
var d = Mathf.Lerp( -0.5f, 0.5f, t );
var v = Axis.U == a ? new Vector3( d, 0, 0 ) : new Vector3( 0, d, 0 );
return v;
}
public static List<float> GetSubDivisions( MeshAxisSubDivider divider, Transform3D quadTransform, Axis axis )
{
if ( divider == null )
{
return new List<float>(){};
}
return divider.GetSubDivisions( quadTransform, axis );
}
public static List<float> GetSubDivisionsU( MeshAxisSubDivider divider, Transform3D quadTransform )
{
return GetSubDivisions( divider, quadTransform, Axis.U );
}
public static List<float> GetSubDivisionsV( MeshAxisSubDivider divider, Transform3D quadTransform )
{
return GetSubDivisions( divider, quadTransform, Axis.V );
}
}
}

View File

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

View File

@ -36,14 +36,19 @@ namespace Rokojori
material.SetShaderParameter( "isFullSphere", octahedralFullSphere ); material.SetShaderParameter( "isFullSphere", octahedralFullSphere );
material.SetShaderParameter( "imposterFrames", Vector2.One * octahedralSides ); material.SetShaderParameter( "imposterFrames", Vector2.One * octahedralSides );
Materials.Set( mb.X_outputMesh, material ); // Materials.Set( mb.X_outputMesh, material );
MaterialSurfaceContainer.SetMaterialInSlot( mb.X_outputMesh, MaterialSlot.MeshSurface, material );
} }
public override void AssignMaterial( List<_XX_BakingPass> passes ) public override void AssignMaterial( List<_XX_BakingPass> passes )
{ {
var mb = multiBaker; var mb = multiBaker;
var material = Materials.Get<ShaderMaterial>( mb.X_outputMesh ); // var material = Materials.Get<ShaderMaterial>( mb.X_outputMesh );
var material = MaterialSurfaceContainer.GetMaterialInSlot<ShaderMaterial>( mb.X_outputMesh, MaterialSlot.MeshSurface );
if ( material == null ) if ( material == null )
{ {

View File

@ -33,13 +33,16 @@ namespace Rokojori
material.CullMode = BaseMaterial3D.CullModeEnum.Disabled; material.CullMode = BaseMaterial3D.CullModeEnum.Disabled;
} }
Materials.Set( mb.X_outputMesh, material ); MaterialSurfaceContainer.SetMaterialInSlot( mb.X_outputMesh, MaterialSlot.MeshSurface, material );
// Materials.Set( mb.X_outputMesh, material );
} }
public override void AssignMaterial( List<_XX_BakingPass> passes ) public override void AssignMaterial( List<_XX_BakingPass> passes )
{ {
var mb = multiBaker; var mb = multiBaker;
var material = Materials.Get<StandardMaterial3D>( mb.X_outputMesh ); // var material = Materials.Get<StandardMaterial3D>( mb.X_outputMesh );
var material = MaterialSurfaceContainer.GetMaterialInSlot<StandardMaterial3D>( mb.X_outputMesh, MaterialSlot.MeshSurface );
material.AlbedoTexture = _XX_BakingPass.Get( passes, BakingTargetType.Albedo, BakingTargetType.Lit ); material.AlbedoTexture = _XX_BakingPass.Get( passes, BakingTargetType.Albedo, BakingTargetType.Lit );

View File

@ -7,16 +7,18 @@ using System;
namespace Rokojori namespace Rokojori
{ {
public enum MaterialSlot
{
None,
MeshSurface,
MeshSurfaceOverride,
Override,
Overlay
}
public abstract class MaterialSurfaceContainer public abstract class MaterialSurfaceContainer
{ {
public enum MaterialSlot
{
None,
MeshSurface,
MeshSurfaceOverride,
Override,
Overlay
}
protected Node3D _owner; protected Node3D _owner;
protected int _surfaceIndex; protected int _surfaceIndex;
@ -29,7 +31,7 @@ namespace Rokojori
} }
public abstract MaterialSlot GetActiveMaterialSlot(); public abstract MaterialSlot GetActiveMaterialSlot();
public abstract Material GetMaterialInSlot( MaterialSlot slot ); public abstract T GetMaterialInSlot<T>( MaterialSlot slot ) where T:Material;
public abstract void SetMaterialInSlot( MaterialSlot slot, Material material ); public abstract void SetMaterialInSlot( MaterialSlot slot, Material material );
public void SetActiveMaterial( Material material ) public void SetActiveMaterial( Material material )
@ -37,9 +39,9 @@ namespace Rokojori
SetMaterialInSlot( GetActiveMaterialSlot(), material ); SetMaterialInSlot( GetActiveMaterialSlot(), material );
} }
public Material GetActiveMaterial() public T GetActiveMaterial<T>() where T:Material
{ {
return GetMaterialInSlot( GetActiveMaterialSlot() ); return (T)GetMaterialInSlot<T>( GetActiveMaterialSlot() );
} }
protected abstract void _MakeUnique( bool materials ); protected abstract void _MakeUnique( bool materials );
@ -86,7 +88,48 @@ namespace Rokojori
public abstract int numSurfaces { get; } public abstract int numSurfaces { get; }
public static void SetMaterialInSlot( Node3D owner, MaterialSlot slot, Material material, int surfaceIndex = 0 )
{
var mc = From( owner, surfaceIndex );
if ( mc == null )
{
return;
}
mc.SetMaterialInSlot( slot, material );
}
public static T GetMaterialInSlot<T>( Node3D owner, MaterialSlot slot, int surfaceIndex = 0 ) where T:Material
{
var mc = From( owner, surfaceIndex );
if ( mc == null )
{
return null;
}
return mc.GetMaterialInSlot<T>( slot );
}
public static MaterialSurfaceContainer From( Node3D owner, int surfaceIndex = -1 )
{
if ( owner is MeshInstance3D mesh )
{
return new MeshSurfaceContainer( mesh, surfaceIndex );
}
if ( owner is MultiMeshInstance3D multi )
{
return new MultiMeshSurfaceContainer( multi, surfaceIndex );
}
return null;
}
} }
public abstract class MaterialSurfaceContainer<T>:MaterialSurfaceContainer where T:Node3D public abstract class MaterialSurfaceContainer<T>:MaterialSurfaceContainer where T:Node3D
@ -102,26 +145,26 @@ namespace Rokojori
public override int numSurfaces => node == null || node.Mesh == null ? -1 : node.Mesh.GetSurfaceCount(); public override int numSurfaces => node == null || node.Mesh == null ? -1 : node.Mesh.GetSurfaceCount();
public override MeshSurfaceContainer.MaterialSlot GetActiveMaterialSlot() public override MaterialSlot GetActiveMaterialSlot()
{ {
if ( node.MaterialOverride != null ) if ( node.MaterialOverride != null )
{ {
return MeshSurfaceContainer.MaterialSlot.Override; return MaterialSlot.Override;
} }
if ( node.Mesh == null || surfaceIndex == -1 ) if ( node.Mesh == null || surfaceIndex == -1 )
{ {
return MeshSurfaceContainer.MaterialSlot.None; return MaterialSlot.None;
} }
if ( node.GetSurfaceOverrideMaterial( surfaceIndex ) != null ) if ( node.GetSurfaceOverrideMaterial( surfaceIndex ) != null )
{ {
return MeshSurfaceContainer.MaterialSlot.MeshSurfaceOverride; return MaterialSlot.MeshSurfaceOverride;
} }
var material = node.Mesh.SurfaceGetMaterial( surfaceIndex ); var material = node.Mesh.SurfaceGetMaterial( surfaceIndex );
return material == null ? MeshSurfaceContainer.MaterialSlot.None : MeshSurfaceContainer.MaterialSlot.MeshSurface; return material == null ? MaterialSlot.None : MaterialSlot.MeshSurface;
} }
public override void SetMaterialInSlot( MaterialSlot slot, Material material ) public override void SetMaterialInSlot( MaterialSlot slot, Material material )
@ -149,7 +192,7 @@ namespace Rokojori
} }
} }
public override Material GetMaterialInSlot( MaterialSlot slot ) public override T GetMaterialInSlot<T>( MaterialSlot slot )
{ {
if ( MaterialSlot.None == slot ) if ( MaterialSlot.None == slot )
{ {
@ -157,19 +200,19 @@ namespace Rokojori
} }
else if ( MaterialSlot.MeshSurface == slot ) else if ( MaterialSlot.MeshSurface == slot )
{ {
return node.Mesh.SurfaceGetMaterial( surfaceIndex ); return (T) node.Mesh.SurfaceGetMaterial( surfaceIndex );
} }
else if ( MaterialSlot.MeshSurfaceOverride == slot ) else if ( MaterialSlot.MeshSurfaceOverride == slot )
{ {
return node.GetSurfaceOverrideMaterial( surfaceIndex ); return (T) node.GetSurfaceOverrideMaterial( surfaceIndex );
} }
else if ( MaterialSlot.Override == slot ) else if ( MaterialSlot.Override == slot )
{ {
return node.MaterialOverride; return (T) node.MaterialOverride;
} }
else if ( MaterialSlot.Overlay == slot ) else if ( MaterialSlot.Overlay == slot )
{ {
return node.MaterialOverlay; return (T) node.MaterialOverlay;
} }
return null; return null;
@ -210,22 +253,22 @@ namespace Rokojori
public override int numSurfaces => node == null || node.Multimesh == null || node.Multimesh.Mesh == null ? -1 : public override int numSurfaces => node == null || node.Multimesh == null || node.Multimesh.Mesh == null ? -1 :
node.Multimesh.Mesh.GetSurfaceCount(); node.Multimesh.Mesh.GetSurfaceCount();
public override MeshSurfaceContainer.MaterialSlot GetActiveMaterialSlot() public override MaterialSlot GetActiveMaterialSlot()
{ {
if ( node.MaterialOverride != null ) if ( node.MaterialOverride != null )
{ {
return MeshSurfaceContainer.MaterialSlot.Override; return MaterialSlot.Override;
} }
if ( node.Multimesh == null || node.Multimesh.Mesh == null || surfaceIndex == -1 ) if ( node.Multimesh == null || node.Multimesh.Mesh == null || surfaceIndex == -1 )
{ {
return MeshSurfaceContainer.MaterialSlot.None; return MaterialSlot.None;
} }
var material = node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex ); var material = node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex );
return material == null ? MeshSurfaceContainer.MaterialSlot.None : MeshSurfaceContainer.MaterialSlot.MeshSurface; return material == null ? MaterialSlot.None : MaterialSlot.MeshSurface;
} }
public override void SetMaterialInSlot( MaterialSlot slot, Material material ) public override void SetMaterialInSlot( MaterialSlot slot, Material material )
@ -249,7 +292,7 @@ namespace Rokojori
} }
} }
public override Material GetMaterialInSlot( MaterialSlot slot ) public override T GetMaterialInSlot<T>( MaterialSlot slot )
{ {
if ( MaterialSlot.None == slot ) if ( MaterialSlot.None == slot )
{ {
@ -257,15 +300,15 @@ namespace Rokojori
} }
else if ( MaterialSlot.MeshSurface == slot ) else if ( MaterialSlot.MeshSurface == slot )
{ {
return node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex ); return (T) node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex );
} }
else if ( MaterialSlot.Override == slot ) else if ( MaterialSlot.Override == slot )
{ {
return node.MaterialOverride; return (T) node.MaterialOverride;
} }
else if ( MaterialSlot.Overlay == slot ) else if ( MaterialSlot.Overlay == slot )
{ {
return node.MaterialOverlay; return (T) node.MaterialOverlay;
} }
return null; return null;

View File

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

View File

@ -48,7 +48,7 @@ namespace Rokojori
} }
[Export] [Export]
public TextureSizeMode textureSizeMode = TextureSizeMode.Custom; public TextureSizeMode textureSizeMode = TextureSizeMode.KeepOriginal;
[Export] [Export]
public Vector2I customTextureSize = new Vector2I( 1024, 1024 ); public Vector2I customTextureSize = new Vector2I( 1024, 1024 );
@ -111,14 +111,8 @@ namespace Rokojori
await CombineMaterials(); await CombineMaterials();
if ( combineMeshes ) await CombineMeshes();
{
await CombineMeshes();
}
else
{
await ReassignMaterials();
}
} }
@ -176,6 +170,12 @@ namespace Rokojori
if ( type == null ) if ( type == null )
{ {
type = MaterialType.From( m ); type = MaterialType.From( m );
if ( type == null )
{
this.LogInfo( "Invalid Type:", m);
}
} }
if ( type == null ) if ( type == null )
@ -337,47 +337,6 @@ namespace Rokojori
return outputMaterial; 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() async Task CombineMeshes()
{ {
var arrayMesh = new ArrayMesh(); var arrayMesh = new ArrayMesh();
@ -390,14 +349,27 @@ namespace Rokojori
var outputMaterials = new List<Material>(); var outputMaterials = new List<Material>();
if ( ! combineMeshes )
{
if ( outputContainer == null )
{
outputContainer = this.CreateChild<Node3D>();
}
outputContainer.DestroyChildren();
}
_materials.ForEach( _materials.ForEach(
( m )=> ( m )=>
{ {
var isCombinedMaterial = _combinedMaterials.ContainsKey( m );
var usedMaterial = isCombinedMaterial ? _combinedMaterials[ m ] : m;
Transform2D? uvTransform = _uvTransform.ContainsKey( m ) ? _uvTransform[ m ] : null; Transform2D? uvTransform = _uvTransform.ContainsKey( m ) ? _uvTransform[ m ] : null;
var surfaces = _materiaList[ m ]; var surfaces = _materiaList[ m ];
this.LogInfo( "Combining for Material", m, surfaces.Count, "meshes" ); this.LogInfo( "Combining for Material", "combined?:",isCombinedMaterial,"material:", usedMaterial, surfaces.Count, "meshes" );
var meshGeometry = new MeshGeometry(); var meshGeometry = new MeshGeometry();
@ -414,32 +386,54 @@ namespace Rokojori
var trsf = s.transform; var trsf = s.transform;
if ( pivot != null ) if ( combineMeshes )
{ {
trsf.Origin -= pivot.GlobalPosition; if ( pivot != null )
} {
trsf.Origin -= pivot.GlobalPosition;
}
smg.ApplyTransform( trsf ); smg.ApplyTransform( trsf );
}
meshGeometry.Add( smg ); meshGeometry.Add( smg );
if ( isCombinedMaterial && ! combineMeshes )
{
meshGeometry.GenerateMesh( Mesh.PrimitiveType.Triangles, arrayMesh );
arrayMesh.SurfaceSetMaterial( index, usedMaterial );
var meshInstance = outputContainer.CreateChild<MeshInstance3D>();
meshInstance.Mesh = arrayMesh;
meshInstance.GlobalTransform = trsf;
meshGeometry = new MeshGeometry();
arrayMesh = new ArrayMesh();
}
} }
); );
var isCombinedMaterial = _combinedMaterials.ContainsKey( m );
if ( isCombinedMaterial ) if ( isCombinedMaterial && combineMeshes )
{ {
this.LogInfo( "Add material groups", m ); this.LogInfo( "Add material groups", m );
combined.Add( _combinedMaterials[ m ], meshGeometry ); combined.Add( _combinedMaterials[ m ], meshGeometry );
return; return;
} }
meshGeometry.GenerateMesh( Mesh.PrimitiveType.Triangles, arrayMesh );
outputMaterials.Add( usedMaterial );
if ( combineMeshes )
{
meshGeometry.GenerateMesh( Mesh.PrimitiveType.Triangles, arrayMesh );
arrayMesh.SurfaceSetMaterial( index, usedMaterial );
arrayMesh.SurfaceSetMaterial( index, m ); index ++;
outputMaterials.Add( m ); }
index ++;
} }
); );
@ -468,16 +462,19 @@ namespace Rokojori
this.LogInfo( "Processing done, adding outputs", arrayMesh.GetSurfaceCount() ); this.LogInfo( "Processing done, adding outputs", arrayMesh.GetSurfaceCount() );
if ( outputMesh == null )
{
this.LogInfo( "Created outputMesh");
outputMesh = this.CreateChild<MeshInstance3D>();
}
this.outputMaterials = outputMaterials.ToArray(); this.outputMaterials = outputMaterials.ToArray();
outputMesh.Mesh = arrayMesh; if ( combineMeshes )
{
if ( outputMesh == null )
{
this.LogInfo( "Created outputMesh");
outputMesh = this.CreateChild<MeshInstance3D>();
}
outputMesh.Mesh = arrayMesh;
}
return; return;
} }

View File

@ -158,14 +158,14 @@ namespace Rokojori
return list; return list;
} }
public static List<Transformable<MeshSurface>> ExtractSurfaces( Node n, List<Transformable<MeshSurface>> list = null, bool trackOwners = false ) public static List<Transformable<MeshSurface>> ExtractSurfaces( Node n, List<Transformable<MeshSurface>> list = null )
{ {
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 owner = mi;
var mesh = mi.Mesh; var mesh = mi.Mesh;
@ -189,7 +189,7 @@ namespace Rokojori
if ( n is MultiMeshInstance3D mmi ) if ( n is MultiMeshInstance3D mmi )
{ {
var owner = trackOwners ? mmi : null; var owner = mmi;
var mm = mmi.Multimesh; var mm = mmi.Multimesh;
for ( var j = 0; j < mm.InstanceCount; j++ ) for ( var j = 0; j < mm.InstanceCount; j++ )

View File

@ -660,6 +660,21 @@ namespace Rokojori
AddTriangle( va, vb, vc, n, n, n, uv, uv, uv ); AddTriangle( va, vb, vc, n, n, n, uv, uv, uv );
} }
public void AddQuad(
VertexAttributes a,
VertexAttributes b,
VertexAttributes c,
VertexAttributes d
)
{
AddQuad(
a.position, b.position, c.position, d.position,
(Vector3) a.normal, (Vector3) b.normal, (Vector3) c.normal, (Vector3) d.normal,
(Vector2) a.uv, (Vector2) b.uv, (Vector2) c.uv, (Vector2) d.uv
);
}
public void AddQuad( public void AddQuad(
Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd, Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd,
Vector3 na, Vector3 nb, Vector3 nc, Vector3 nd, Vector3 na, Vector3 nb, Vector3 nc, Vector3 nd,
@ -667,6 +682,18 @@ namespace Rokojori
) )
{ {
/*
0:a -- 1:b
| |
2:c -- 3:d
faces:
1: 0 1 2
2: 2 3 0
*/
var index = vertices.Count; var index = vertices.Count;
Lists.Add( vertices, va, vb, vc, vd ); Lists.Add( vertices, va, vb, vc, vd );
@ -675,8 +702,10 @@ namespace Rokojori
Lists.Add( indices, index, index + 1, index + 2 ); Lists.Add( indices, index, index + 1, index + 2 );
Lists.Add( indices, index + 2, index + 3, index ); Lists.Add( indices, index + 2, index + 3, index );
} }
public void AddQuad( Quaternion rotation, float size, Box2 rectangle ) public void AddQuad( Quaternion rotation, float size, Box2 rectangle )
{ {
AddQuad( rotation, size, rectangle.min, rectangle.max ); AddQuad( rotation, size, rectangle.min, rectangle.max );
@ -702,6 +731,112 @@ namespace Rokojori
} }
} }
public void AddQuadWithCustomDivisions( Quaternion rotation, float size, Vector2 uv00, Vector2 uv11, List<float> uDivisions, List<float> vDivisions )
{
if ( uDivisions.Count == 0 && vDivisions.Count == 0 )
{
AddQuad( rotation, size, uv00, uv11 );
return;
}
var l = size * 0.5f;
var normal = Vector3.Back * rotation;
var points = new List<Vector3>
{
new Vector3( l, -l, 0 ), new Vector3( -l, -l, 0 ),
new Vector3( -l, l, 0 ), new Vector3( l, l, 0 )
};
for ( int i = 0; i < points.Count; i++ )
{
points[ i ] = points[ i ] * rotation;
}
var uv10 = new Vector2( uv11.X, uv00.Y );
var uv01 = new Vector2( uv00.X, uv11.Y );
var v10 = VertexAttributes.Create( points[ 0 ], uv10, normal );
var v00 = VertexAttributes.Create( points[ 1 ], uv00, normal );
var v01 = VertexAttributes.Create( points[ 2 ], uv01, normal );
var v11 = VertexAttributes.Create( points[ 3 ], uv11, normal );
var uSegments = new List<float>();
uSegments.Add( 0 );
uSegments.AddRange( uDivisions );
uSegments.Add( 1 );
var vSegments = new List<float>();
vSegments.Add( 0 );
vSegments.AddRange( vDivisions );
vSegments.Add( 1 );
for ( int i = 0; i < ( uSegments.Count - 1 ); i++ )
{
var i0 = uSegments[ i ];
var i1 = uSegments[ i + 1 ];
var t0 = v10.Lerp( v00, i0 );
var t1 = v10.Lerp( v00, i1 );
var b0 = v01.Lerp( v11, i0 );
var b1 = v01.Lerp( v11, i1 );
for ( int j = 0; j < ( vSegments.Count - 1 ); j++ )
{
var j0 = vSegments[ j ];
var j1 = vSegments[ j + 1 ];
var tb00 = t0.Lerp( b0, j0 );
var tb10 = t1.Lerp( b1, j0 );
var tb01 = t0.Lerp( b0, j1 );
var tb11 = t1.Lerp( b1, j1 );
AddQuad( tb10, tb00, tb01, tb11 );
}
}
}
public void AddQuadSubdivided( Quaternion rotation, float size, Vector2 uv00, Vector2 uv11, int uDivisions = 0, int vDivisions = 0 )
{
uDivisions = Mathf.Max( 0, uDivisions );
vDivisions = Mathf.Max( 0, vDivisions );
if ( uDivisions == 0 && vDivisions == 0 )
{
AddQuad( rotation, size, uv00, uv11 );
return;
}
var mg = CreateFromUVFunction(
( uv ) =>
{
var xy = uv * size - Vector2.One * size / 2f;
var pose = new Pose();
pose.position = Math3D.XY( xy );
pose.rotation = rotation;
return pose;
},
uDivisions + 2, vDivisions + 2
);
var uvTransform = new Transform2D();
uvTransform.Origin = uv00;
uvTransform = uvTransform.ScaledLocal( uv11 - uv00 );
mg.ApplyUVTransform( uvTransform );
Add( mg );
}
public void AddQuad( Quaternion rotation, float size, Vector2 uv00, Vector2 uv11 ) public void AddQuad( Quaternion rotation, float size, Vector2 uv00, Vector2 uv11 )
{ {
var l = size * 0.5f; var l = size * 0.5f;

View File

@ -0,0 +1,57 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
namespace Rokojori
{
public class VertexAttributes
{
public Vector3 position;
public Vector3? normal;
public Vector2? uv;
public Vector2? uv2 = null;
public Color? color = null;
public static VertexAttributes Create( Vector3 position, Vector2 uv, Vector3 normal )
{
var va = new VertexAttributes();
va.position = position;
va.uv = uv;
va.normal = normal;
return va;
}
public VertexAttributes Lerp( VertexAttributes other, float t )
{
var lerped = new VertexAttributes();
lerped.position = position.Lerp( other.position, t );
if ( normal != null )
{
lerped.normal = ((Vector3)normal).Lerp( (Vector3)other.normal, t );
}
if ( uv != null )
{
lerped.uv = ((Vector2)uv).Lerp( (Vector2)other.uv, t );
}
if ( uv2 != null )
{
lerped.uv2 = ((Vector2)uv2).Lerp( (Vector2)other.uv2, t );
}
if ( color != null )
{
lerped.color = ((Color)color).Lerp( (Color)other.color, t );
}
return lerped;
}
}
}

View File

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

View File

@ -50,11 +50,11 @@ namespace Rokojori
if ( useGlobalRotation ) if ( useGlobalRotation )
{ {
Math3D.SetGlobalRotationTo( node3D, rotation.Normalized() ); Math3D.SetGlobalRotationTo( node3D, rotation.GetNormalized() );
} }
else else
{ {
node3D.Quaternion = rotation; node3D.Quaternion = rotation.GetNormalized();
} }
node3D.Scale = scale; node3D.Scale = scale;

View File

@ -63,7 +63,7 @@ namespace Rokojori
public void CopyFromSampled( TextureCombinerBuffer source, int x, int y, int w, int h ) public void CopyFromSampled( TextureCombinerBuffer source, int x, int y, int w, int h )
{ {
RJLog.Log( "Copy Sampled", x,y, w, h ); // RJLog.Log( "Copy Sampled", x,y, w, h );
for ( int i = 0; i < w; i ++ ) for ( int i = 0; i < w; i ++ )
{ {
@ -92,7 +92,7 @@ namespace Rokojori
var mergeSize = new Vector2( w, h ); var mergeSize = new Vector2( w, h );
var gridSize = (Vector2I)( mergeSize / alignment ); var gridSize = (Vector2I)( mergeSize / alignment );
RJLog.Log( "GridMerge" ); // RJLog.Log( "GridMerge" );
for ( int i = 0; i < textures.Count; i++ ) for ( int i = 0; i < textures.Count; i++ )
{ {
@ -101,7 +101,7 @@ namespace Rokojori
positions.Add( position ); positions.Add( position );
sizes.Add( gridSize ); sizes.Add( gridSize );
RJLog.Log( i, position, gridSize ); // RJLog.Log( i, position, gridSize );
} }

View File

@ -0,0 +1,153 @@
vec4 quaternionFromMatrix( mat3 m )
{
vec4 qa = vec4( 0.0, 0.0, 0.0, 1.0 );
float trace = m[ 0 ][ 0 ] + m[ 1 ][ 1 ] + m[ 2 ][ 2 ];
if ( trace > 0.0 )
{
float s = 0.5 / sqrt( trace + 1.0 );
qa.w = 0.25 / s;
qa.x = ( m[ 1 ][ 2 ] - m[ 2 ][ 1 ] ) * s;
qa.y = ( m[ 2 ][ 0 ] - m[ 0 ][ 2 ] ) * s;
qa.z = ( m[ 0 ][ 1 ] - m[ 1 ][ 0 ] ) * s;
}
else if ( m[ 0 ][ 0 ] > m[ 1 ][ 1 ] && m[ 0 ][ 0 ] > m[ 2 ][ 2 ] )
{
float s = 2.0 * sqrt( 1.0 + m[ 0 ][ 0 ] - m[ 1 ][ 1 ] - m[ 2 ][ 2 ] );
qa.w = ( m[ 1 ][ 2 ] - m[ 2 ][ 1 ] ) / s;
qa.x = 0.25 * s;
qa.y = ( m[ 1 ][ 0 ] + m[ 0 ][ 1 ] ) / s;
qa.z = ( m[ 2 ][ 0 ] + m[ 0 ][ 2 ] ) / s;
}
else if ( m[ 1 ][ 1 ] > m[ 2 ][ 2 ] )
{
float s = 2.0 * sqrt( 1.0 + m[ 1 ][ 1 ] - m[ 0 ][ 0 ] - m[ 2 ][ 2 ] );
qa.w = ( m[ 2 ][ 0 ] - m[ 0 ][ 2 ] ) / s;
qa.x = ( m[ 1 ][ 0 ] + m[ 0 ][ 1 ] ) / s;
qa.y = 0.25 * s;
qa.z = ( m[ 2 ][ 1 ] + m[ 1 ][ 2 ] ) / s;
}
else
{
float s = 2.0 * sqrt( 1.0 + m[ 2 ][ 2 ] - m[ 0 ][ 0 ] - m[ 1 ][ 1 ] );
qa.w = ( m[ 0 ][ 1 ] - m[ 1 ][ 0 ] ) / s;
qa.x = ( m[ 2 ][ 0 ] + m[ 0 ][ 2 ] ) / s;
qa.y = ( m[ 2 ][ 1 ] + m[ 1 ][ 2 ] ) / s;
qa.z = 0.25 * s;
}
return qa;
}
vec4 quaternionMultiply( vec4 a, vec4 b )
{
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
float qax = a.x;
float qay = a.y;
float qaz = a.z;
float qaw = a.w;
float qbx = b.x;
float qby = b.y;
float qbz = b.z;
float qbw = b.w;
vec4 q = vec4( 0.0, 0.0, 0.0, 0.0 );
q.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
q.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
q.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
q.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
return q;
}
vec4 quaternionSlerp( vec4 qa, vec4 qb, float t )
{
if ( t == 0.0 )
{
return qa;
}
if ( t == 1.0 )
{
return qb;
}
float x = qa.x;
float y = qa.y;
float z = qa.z;
float w = qa.w;
float cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
if ( cosHalfTheta < 0.0 )
{
qa.w = - qb.w;
qa.x = - qb.x;
qa.y = - qb.y;
qa.z = - qb.z;
cosHalfTheta = - cosHalfTheta;
}
else
{
qa = qb;
}
if ( cosHalfTheta >= 1.0 )
{
qa.w = w;
qa.x = x;
qa.y = y;
qa.z = z;
return qa;
}
float sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
if ( sqrSinHalfTheta <= 0.000001 )
{
float s = 1.0 - t;
qa.w = s * w + t * qa.w;
qa.x = s * x + t * qa.x;
qa.y = s * y + t * qa.y;
qa.z = s * z + t * qa.z;
qa = normalize( qa );
return qa;
}
float sinHalfTheta = sqrt( sqrSinHalfTheta );
float halfTheta = atan( sinHalfTheta, cosHalfTheta );
float ratioA = sin( ( 1.0 - t ) * halfTheta ) / sinHalfTheta;
float ratioB = sin( t * halfTheta ) / sinHalfTheta;
qa.w = ( w * ratioA + qa.w * ratioB );
qa.x = ( x * ratioA + qa.x * ratioB );
qa.y = ( y * ratioA + qa.y * ratioB );
qa.z = ( z * ratioA + qa.z * ratioB );
return qa;
}

View File

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

View File

@ -1,3 +1,4 @@
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Quaternion.gdshaderinc"
vec3 applyMatrix( vec3 v, mat4 m ) vec3 applyMatrix( vec3 v, mat4 m )
{ {
@ -43,7 +44,7 @@ vec3 localToViewDirection( vec3 local, mat3 _MODELVIEW_NORMAL_MATRIX )
vec3 worldToLocal( vec3 world, mat4 _MODEL_MATRIX ) vec3 worldToLocal( vec3 world, mat4 _MODEL_MATRIX )
{ {
mat4 inversedMatrix = inverse( _MODEL_MATRIX ); mat4 inversedMatrix = inverse( _MODEL_MATRIX );
return applyMatrix( world, inv ); return applyMatrix( world, inversedMatrix );
} }
vec3 worldToLocalDirection( vec3 world, mat4 _MODEL_MATRIX ) vec3 worldToLocalDirection( vec3 world, mat4 _MODEL_MATRIX )
@ -142,9 +143,14 @@ vec2 worldToScreen( vec3 world, mat4 _VIEW_MATRIX, mat4 _PROJECTION_MATRIX )
} }
vec3 extractScale( mat3 _MODEL_NORMAL_MATRIX ) vec3 extractTranslation( mat4 matrix )
{ {
mat3 m = _MODEL_NORMAL_MATRIX; return vec3( matrix[ 3 ][ 0 ], matrix[ 3 ][ 1 ], matrix[ 3 ][ 2 ] );
}
vec3 extractScale( mat3 matrix )
{
mat3 m = matrix;
float x = length( vec3( m[ 0 ][ 0 ], m[ 1 ][ 0 ], m[ 2 ][ 0 ] ) ); float x = length( vec3( m[ 0 ][ 0 ], m[ 1 ][ 0 ], m[ 2 ][ 0 ] ) );
float y = length( vec3( m[ 0 ][ 1 ], m[ 1 ][ 1 ], m[ 2 ][ 1 ] ) ); float y = length( vec3( m[ 0 ][ 1 ], m[ 1 ][ 1 ], m[ 2 ][ 1 ] ) );
@ -153,6 +159,48 @@ vec3 extractScale( mat3 _MODEL_NORMAL_MATRIX )
return vec3( x, y, z ); return vec3( x, y, z );
} }
vec3 extractScale( mat4 matrix )
{
mat4 m = matrix;
float x = length( vec3( m[ 0 ][ 0 ], m[ 1 ][ 0 ], m[ 2 ][ 0 ] ) );
float y = length( vec3( m[ 0 ][ 1 ], m[ 1 ][ 1 ], m[ 2 ][ 1 ] ) );
float z = length( vec3( m[ 0 ][ 2 ], m[ 1 ][ 2 ], m[ 2 ][ 2 ] ) );
return vec3( x, y, z );
}
mat3 extractRotationMatrix( mat4 m )
{
vec3 x = normalize( m[ 0 ].xyz );
vec3 y = normalize( m[ 1 ].xyz );
vec3 z = normalize( m[ 2 ].xyz );
return mat3( x, y, z );
}
vec4 extractQuaternion( mat4 m )
{
mat3 rotationMatrix = extractRotationMatrix( m );
return quaternionFromMatrix( rotationMatrix );
}
float extractRotationX( mat4 matrix )
{
return atan( matrix[2][1], matrix[2][2] );
}
float extractRotationY( mat4 matrix )
{
return atan(-matrix[2][0], sqrt(matrix[2][1] * matrix[2][1] + matrix[2][2] * matrix[2][2]));
}
float extractRotationZ( mat4 matrix )
{
return atan(matrix[1][0], matrix[0][0]);
}
vec2 tilingOffset( vec2 uv, vec4 tilingOffset ) vec2 tilingOffset( vec2 uv, vec4 tilingOffset )
{ {
uv *= tilingOffset.xy; uv *= tilingOffset.xy;
@ -378,13 +426,15 @@ mat4 identity_m4()
mat4 translate_m4( vec3 translation ) mat4 translate_m4( vec3 translation )
{ {
return mat4( return mat4(
vec4( 1, 0, 0, translation.x ), vec4( 1, 0, 0, 0 ),
vec4( 0, 1, 0, translation.y ), vec4( 0, 1, 0, 0 ),
vec4( 0, 0, 1, translation.z ), vec4( 0, 0, 1, 0 ),
vec4( 0, 0, 0, 1 ) vec4( translation.x , translation.y, translation.z, 1 )
); );
} }
mat4 scale_m4( vec3 scale ) mat4 scale_m4( vec3 scale )
{ {
return mat4( return mat4(
@ -403,8 +453,8 @@ mat4 rotationX_m4( float radiansAngle )
return mat4( return mat4(
vec4( 1, 0, 0, 0 ), vec4( 1, 0, 0, 0 ),
vec4( 0, c, -s, 0 ), vec4( 0, c, s, 0 ),
vec4( 0, s, c, 0 ), vec4( 0, -s, c, 0 ),
vec4( 0, 0, 0, 1 ) vec4( 0, 0, 0, 1 )
); );
} }
@ -415,9 +465,9 @@ mat4 rotationY_m4( float radiansAngle )
float s = sin( radiansAngle ); float s = sin( radiansAngle );
return mat4( return mat4(
vec4( c, 0, s, 0 ), vec4( c, 0,-s, 0 ),
vec4( 0, 1, 0, 0 ), vec4( 0, 1, 0, 0 ),
vec4( -s, 0, c, 0 ), vec4( s, 0, c, 0 ),
vec4( 0, 0, 0, 1 ) vec4( 0, 0, 0, 1 )
); );
} }
@ -428,9 +478,81 @@ mat4 rotationZ_m4( float radiansAngle )
float s = sin( radiansAngle ); float s = sin( radiansAngle );
return mat4( return mat4(
vec4( c, -s, 0, 0 ), vec4( c, s, 0, 0 ),
vec4( s, c, 0, 0 ), vec4(-s, c, 0, 0 ),
vec4( 0, 0, 1, 0 ), vec4( 0, 0, 1, 0 ),
vec4( 0, 0, 0, 1 ) vec4( 0, 0, 0, 1 )
); );
}
mat3 quaternionToRotationMatrix( vec4 q )
{
float x = q.x;
float y = q.y;
float z = q.z;
float w = q.w;
float x2 = x + x;
float y2 = y + y;
float z2 = z + z;
float xx = x * x2;
float xy = x * y2;
float xz = x * z2;
float yy = y * y2;
float yz = y * z2;
float zz = z * z2;
float wx = w * x2;
float wy = w * y2;
float wz = w * z2;
mat3 matrix = mat3(
vec3(
( 1.0 - ( yy + zz ) ),
( xy + wz ),
( xz - wy )
),
vec3(
( xy - wz ),
( 1.0 - ( xx + zz ) ),
( yz + wx )
),
vec3(
( xz + wy ),
( yz - wx ),
( 1.0 - ( xx + yy ) )
)
);
return matrix;
}
mat4 TRS( vec3 translation, vec4 rotation, vec3 scale )
{
return translate_m4( translation ) * mat4( quaternionToRotationMatrix( rotation ) ) * scale_m4( scale );
}
mat4 mixTRS( mat4 a, mat4 b, float t )
{
vec3 oA = extractTranslation( a );
vec3 oB = extractTranslation( b );
vec3 sA = extractScale( a );
vec3 sB = extractScale( b );
vec4 rA = extractQuaternion( a );
vec4 rB = extractQuaternion( b );
vec3 o = mix( oA, oB, t );
vec3 s = mix( sA, sB, t );
vec4 r = quaternionSlerp( rA, rB, t );
return TRS( o, r, s );
} }

View File

@ -28,7 +28,7 @@ leftButton = ExtResource("4_nn62x")
rightButton = ExtResource("7_r8nl0") rightButton = ExtResource("7_r8nl0")
upButton = ExtResource("9_sydsp") upButton = ExtResource("9_sydsp")
downButton = ExtResource("2_jknb0") downButton = ExtResource("2_jknb0")
moveSpeed = 1.0 moveSpeed = 10.0
mouseMovementEnabled = true mouseMovementEnabled = true
minimizeDistanceOnMovement = true minimizeDistanceOnMovement = true
mouseMovementYawSpeed = 0.2 mouseMovementYawSpeed = 0.2