625 lines
14 KiB
C#
625 lines
14 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using System;
|
|
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
public class MeshGeometry
|
|
{
|
|
public List<Vector3> vertices = new List<Vector3>();
|
|
public List<int> indices = new List<int>();
|
|
|
|
public List<Vector3> normals;
|
|
public List<Vector2> uvs;
|
|
public List<Vector2> uv2s;
|
|
public List<Color> colors;
|
|
|
|
public int numTriangles => indices.Count / 3;
|
|
|
|
|
|
public static MeshGeometry From( MeshInstance3D meshInstance3D )
|
|
{
|
|
return From( (ArrayMesh)meshInstance3D.Mesh, meshInstance3D.GlobalTransform );
|
|
}
|
|
|
|
public static MeshGeometry From( ArrayMesh mesh, Transform3D? trsf = null )
|
|
{
|
|
var mg = new MeshGeometry();
|
|
|
|
var arrays = mesh.SurfaceGetArrays( 0 );
|
|
|
|
var vertices = arrays[ (int) Mesh.ArrayType.Vertex ];
|
|
|
|
if ( Variant.Type.Nil != vertices.VariantType )
|
|
{
|
|
mg.vertices = new List<Vector3>( vertices.AsVector3Array() );
|
|
}
|
|
|
|
var normals = arrays[ (int) Mesh.ArrayType.Normal ];
|
|
|
|
if ( Variant.Type.Nil != normals.VariantType )
|
|
{
|
|
mg.normals = new List<Vector3>( normals.AsVector3Array() );
|
|
}
|
|
|
|
var uvs = arrays[ (int) Mesh.ArrayType.TexUV ];
|
|
|
|
if ( Variant.Type.Nil != uvs.VariantType )
|
|
{
|
|
mg.uvs = new List<Vector2>( uvs.AsVector2Array() );
|
|
}
|
|
|
|
var uv2s = arrays[ (int) Mesh.ArrayType.TexUV2 ];
|
|
|
|
if ( Variant.Type.Nil != uv2s.VariantType )
|
|
{
|
|
mg.uv2s = new List<Vector2>( uv2s.AsVector2Array() );
|
|
}
|
|
|
|
var colors = arrays[ (int) Mesh.ArrayType.Color ];
|
|
|
|
if ( Variant.Type.Nil != colors.VariantType )
|
|
{
|
|
mg.colors = new List<Color>( colors.AsColorArray() );
|
|
}
|
|
|
|
var indices = arrays[ (int) Mesh.ArrayType.Index ];
|
|
|
|
if ( Variant.Type.Nil != indices.VariantType )
|
|
{
|
|
mg.indices = new List<int>( indices.AsInt32Array() );
|
|
}
|
|
|
|
if ( trsf != null )
|
|
{
|
|
mg.ApplyTransform( (Transform3D)trsf );
|
|
}
|
|
|
|
return mg;
|
|
}
|
|
|
|
public void ApplyTransform( Transform3D trsf )
|
|
{
|
|
for ( int i = 0; i < vertices.Count; i++ )
|
|
{
|
|
vertices[ i ] = trsf * vertices[ i ];
|
|
normals[ i ] = trsf.Basis.GetRotationQuaternion() * normals[ i ];
|
|
}
|
|
}
|
|
|
|
public void BlendNormals( Vector3 direction, float amount )
|
|
{
|
|
if ( amount <= 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( amount >= 1 )
|
|
{
|
|
for ( int i = 0; i < normals.Count; i++ )
|
|
{
|
|
normals[ i ] = direction;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
for ( int i = 0; i < normals.Count; i++ )
|
|
{
|
|
normals[ i ] = Math3D.BlendNormals( normals[ i ], direction, amount );
|
|
}
|
|
}
|
|
|
|
public void Offset( Vector3 offset )
|
|
{
|
|
for ( int i = 0; i < vertices.Count; i++ )
|
|
{
|
|
vertices[ i ] = vertices[ i ] + offset;
|
|
}
|
|
}
|
|
|
|
public void ForEachTriangle( Action<int,int,int,int> callback )
|
|
{
|
|
var index = 0;
|
|
|
|
for ( int i = 0; i < indices.Count; i += 3 )
|
|
{
|
|
var a = indices[ i + 0 ];
|
|
var b = indices[ i + 1 ];
|
|
var c = indices[ i + 2 ];
|
|
|
|
callback( index, a, b, c );
|
|
|
|
index ++;
|
|
}
|
|
}
|
|
|
|
static int GetUVIndex( int u, int v, int segments )
|
|
{
|
|
return u * ( segments + 1 ) + v;
|
|
}
|
|
|
|
|
|
public static MeshGeometry CreateFromUVFunction( Func<Vector2,Pose> uv, int uSegments, int vSegments )
|
|
{
|
|
var mg = new MeshGeometry();
|
|
|
|
for ( int i = 0; i <= uSegments; i++ )
|
|
{
|
|
var uI = (float)i / uSegments;
|
|
|
|
for ( int j = 0; j <= vSegments; j++ )
|
|
{
|
|
var vJ = (float)j / vSegments;
|
|
|
|
var uvIJ = new Vector2( uI, vJ );
|
|
|
|
var pose = uv( uvIJ );
|
|
|
|
mg.vertices.Add( pose.position );
|
|
mg.normals.Add( pose.up );
|
|
mg.uvs.Add( uvIJ );
|
|
}
|
|
}
|
|
|
|
|
|
for ( int i = 0; i < uSegments; i++ )
|
|
{
|
|
var u0 = i;
|
|
var u1 = i + 1;
|
|
|
|
for ( int j = 0; j < vSegments; j++ )
|
|
{
|
|
var v0 = j;
|
|
var v1 = j + 1;
|
|
|
|
var a = GetUVIndex( u0, v0, vSegments );
|
|
var b = GetUVIndex( u1, v0, vSegments );
|
|
var c = GetUVIndex( u1, v1, vSegments );
|
|
var d = GetUVIndex( u0, v1, vSegments );
|
|
|
|
mg.AddTriangle( a, b, d );
|
|
mg.AddTriangle( b, c, d );
|
|
|
|
// mg.AddTriangle( d, b, a );
|
|
// mg.AddTriangle( d, c, b );
|
|
}
|
|
}
|
|
|
|
return mg;
|
|
|
|
}
|
|
|
|
|
|
public MeshGeometry UniqueTriangles()
|
|
{
|
|
var mg = new MeshGeometry();
|
|
|
|
mg.Initialize( true, true, colors != null, uv2s != null );
|
|
|
|
if ( colors != null )
|
|
{
|
|
mg.colors = new List<Color>();
|
|
}
|
|
|
|
if ( uv2s != null )
|
|
{
|
|
mg.uv2s = new List<Vector2>();
|
|
}
|
|
|
|
ForEachTriangle(
|
|
( index, a, b, c )=>
|
|
{
|
|
var vA = vertices[ a ];
|
|
var vB = vertices[ b ];
|
|
var vC = vertices[ c ];
|
|
|
|
var uvA = uvs[ a ];
|
|
var uvB = uvs[ b ];
|
|
var uvC = uvs[ c ];
|
|
|
|
var nA = normals[ a ];
|
|
var nB = normals[ b ];
|
|
var nC = normals[ c ];
|
|
|
|
mg.AddTriangle(
|
|
vA, vB, vC,
|
|
nA, nB, nC,
|
|
uvA, uvB, uvC
|
|
);
|
|
|
|
if ( colors != null )
|
|
{
|
|
Lists.Add( mg.colors, colors[ a ], colors[ b ], colors[ c ] );
|
|
}
|
|
|
|
if ( uv2s != null )
|
|
{
|
|
Lists.Add( mg.uv2s, uv2s[ a ], uv2s[ b ], uv2s[ c ] );
|
|
}
|
|
|
|
}
|
|
);
|
|
|
|
return mg;
|
|
}
|
|
|
|
public void SetTriangleUVs( int triangleIndex, Vector2 uv )
|
|
{
|
|
var i = triangleIndex * 3;
|
|
|
|
var a = indices[ i + 0 ];
|
|
var b = indices[ i + 1 ];
|
|
var c = indices[ i + 2 ];
|
|
|
|
uvs[ a ] = uv;
|
|
uvs[ b ] = uv;
|
|
uvs[ c ] = uv;
|
|
}
|
|
|
|
public void SetTriangleNormal( int triangleIndex, Vector3 normal )
|
|
{
|
|
var i = triangleIndex * 3;
|
|
|
|
var a = indices[ i + 0 ];
|
|
var b = indices[ i + 1 ];
|
|
var c = indices[ i + 2 ];
|
|
|
|
normals[ a ] = normal;
|
|
normals[ b ] = normal;
|
|
normals[ c ] = normal;
|
|
}
|
|
|
|
public void SetTriangleColor( int triangleIndex, Color color )
|
|
{
|
|
var i = triangleIndex * 3;
|
|
|
|
var a = indices[ i + 0 ];
|
|
var b = indices[ i + 1 ];
|
|
var c = indices[ i + 2 ];
|
|
|
|
colors[ a ] = color;
|
|
colors[ b ] = color;
|
|
colors[ c ] = color;
|
|
}
|
|
|
|
public MeshGeometry( bool normals = true, bool uvs = true, bool colors = false, bool uvs2 = false )
|
|
{
|
|
Initialize( normals, uvs, colors, uvs2 );
|
|
}
|
|
|
|
public void Initialize( bool normals = true, bool uvs = true, bool colors = false, bool uvs2 = false )
|
|
{
|
|
this.normals = normals ? new List<Vector3>() : null;
|
|
this.uvs = uvs ? new List<Vector2>() : null;
|
|
this.uv2s = uvs2 ? new List<Vector2>() : null;
|
|
this.colors = colors ? new List<Color>() : null;
|
|
}
|
|
|
|
public Vector3 GetRawNormal( int triangleIndex )
|
|
{
|
|
var va = vertices[ indices[ triangleIndex * 3 ] ];
|
|
var vb = vertices[ indices[ triangleIndex * 3 + 1] ];
|
|
var vc = vertices[ indices[ triangleIndex * 3 + 2 ] ];
|
|
|
|
return Math3D.ComputeNormal( va, vb, vc );
|
|
}
|
|
|
|
public void ComputeNormals()
|
|
{
|
|
var dl = new DictionaryList<int,Vector3>();
|
|
|
|
ForEachTriangle(
|
|
( t, va, vb, vc)=>
|
|
{
|
|
var normal = GetRawNormal( t );
|
|
|
|
dl.Add( va, normal );
|
|
dl.Add( vb, normal );
|
|
dl.Add( vc, normal );
|
|
}
|
|
);
|
|
|
|
foreach ( var e in dl )
|
|
{
|
|
var normalIndex = e.Key;
|
|
var normal = Math3D.Average( e.Value );
|
|
|
|
normals[ normalIndex ] = normal;
|
|
}
|
|
}
|
|
|
|
public MeshGeometry Clone()
|
|
{
|
|
var mg = new MeshGeometry();
|
|
|
|
mg.vertices = Lists.Clone( vertices );
|
|
mg.indices = Lists.Clone( indices );
|
|
mg.normals = Lists.Clone( normals );
|
|
|
|
mg.uvs = Lists.Clone( uvs );
|
|
mg.uv2s = Lists.Clone( uv2s );
|
|
mg.colors = Lists.Clone( colors );
|
|
|
|
return mg;
|
|
}
|
|
|
|
public void FlipNormalDirection()
|
|
{
|
|
for ( int i = 0; i < normals.Count; i++ )
|
|
{
|
|
normals[ i ] = -normals[ i ];
|
|
}
|
|
|
|
for ( int i =0 ; i < indices.Count; i += 3 )
|
|
{
|
|
var b = indices[ i ];
|
|
indices[ i ] = indices[ i + 2 ];
|
|
indices[ i + 2 ] = b;
|
|
}
|
|
}
|
|
|
|
public void Add( MeshGeometry mg )
|
|
{
|
|
var mappedIndices = new Dictionary<int,int>();
|
|
|
|
for ( int i = 0; i < mg.indices.Count; i++ )
|
|
{
|
|
var mgIndex = mg.indices[ i ];
|
|
|
|
if ( ! mappedIndices.ContainsKey( mgIndex ) )
|
|
{
|
|
var newIndex = vertices.Count;
|
|
|
|
if ( mgIndex >= mg.vertices.Count || mgIndex < 0 )
|
|
{
|
|
RJLog.Log( "Out of range:", i, ">>", mgIndex, mg.vertices.Count, mg.indices );
|
|
}
|
|
|
|
var v = mg.vertices[ mgIndex ];
|
|
|
|
vertices.Add( v );
|
|
|
|
if ( normals != null && mg.normals != null)
|
|
{
|
|
normals.Add( mg.normals[ mgIndex ] );
|
|
}
|
|
|
|
if ( uvs != null && mg.uvs != null)
|
|
{
|
|
uvs.Add( mg.uvs[ mgIndex ] );
|
|
}
|
|
|
|
if ( colors != null && mg.colors != null)
|
|
{
|
|
colors.Add( mg.colors[ mgIndex ] );
|
|
}
|
|
|
|
if ( uv2s != null && mg.uv2s != null)
|
|
{
|
|
uv2s.Add( mg.uv2s[ mgIndex ] );
|
|
}
|
|
|
|
|
|
mappedIndices[ mgIndex ] = newIndex;
|
|
}
|
|
|
|
indices.Add( mappedIndices[ mgIndex ] );
|
|
}
|
|
}
|
|
|
|
|
|
public void AddTriangle( int a, int b, int c, bool flip = false )
|
|
{
|
|
if ( flip )
|
|
{
|
|
Lists.Add( indices, c, b, a );
|
|
}
|
|
else
|
|
{
|
|
Lists.Add( indices, a, b, c );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public void AddTriangle(
|
|
Vector3 va, Vector3 vb, Vector3 vc,
|
|
Vector3 na, Vector3 nb, Vector3 nc,
|
|
Vector2 uva, Vector2 uvb, Vector2 uvc
|
|
)
|
|
{
|
|
var index = vertices.Count;
|
|
Lists.Add( vertices, va, vb, vc );
|
|
Lists.Add( normals, na, nb, nc );
|
|
Lists.Add( uvs, uva, uvb, uvc );
|
|
Lists.Add( indices, index, index + 1, index + 2 );
|
|
}
|
|
|
|
|
|
|
|
public void AddTriangle(
|
|
Vector3 va, Vector3 vb, Vector3 vc,
|
|
Vector2 uva, Vector2 uvb, Vector2 uvc
|
|
)
|
|
{
|
|
var n = Vector3.Up;
|
|
|
|
AddTriangle( va, vb, vc,
|
|
n, n, n,
|
|
uva, uvb, uvc );
|
|
}
|
|
|
|
|
|
|
|
public void AddTriangle( Vector3 va, Vector3 vb, Vector3 vc )
|
|
{
|
|
var n = Vector3.Up;
|
|
var uv = Vector2.Zero;
|
|
|
|
AddTriangle( va, vb, vc, n, n, n, uv, uv, uv );
|
|
}
|
|
|
|
public void AddQuad(
|
|
Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd,
|
|
Vector3 na, Vector3 nb, Vector3 nc, Vector3 nd,
|
|
Vector2 uva, Vector2 uvb, Vector2 uvc, Vector2 uvd
|
|
)
|
|
{
|
|
AddTriangle( va, vb, vc, na, nb, nc, uva, uvb, uvc );
|
|
AddTriangle( vc, vd, va, nc, nd, na, uvc, uvd, uva );
|
|
}
|
|
|
|
public void AddQuad( Quaternion rotation, float size, Rect2 rectangle )
|
|
{
|
|
AddQuad( rotation, size, rectangle.Position, rectangle.End );
|
|
}
|
|
|
|
public void AddQuad( Quaternion rotation, float size, Vector2 uv00, Vector2 uv11 )
|
|
{
|
|
var l = size * 0.5f;
|
|
|
|
var normal = Vector3.Forward * 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 );
|
|
|
|
AddQuad(
|
|
points[ 0 ], points[ 1 ], points[ 2 ], points[ 3 ],
|
|
normal, normal, normal, normal,
|
|
uv00, uv10, uv11, uv10
|
|
);
|
|
|
|
}
|
|
|
|
public void AddQuad( int lt, int rt, int lb, int rb, bool flip = false )
|
|
{
|
|
if ( flip )
|
|
{
|
|
AddQuad( rt, lt, rb, lb, false );
|
|
}
|
|
else
|
|
{
|
|
Lists.Add( indices, lb, rt, lt, rt, lb, rb );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public void AddQuad(
|
|
Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd,
|
|
Vector2 uva, Vector2 uvb, Vector2 uvc, Vector2 uvd
|
|
)
|
|
{
|
|
|
|
AddTriangle( va, vb, vc, uva, uvb, uvc );
|
|
AddTriangle( vc, vd, va, uvc, uvd, uva );
|
|
}
|
|
|
|
public void AddQuad( Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd )
|
|
{
|
|
AddQuad(
|
|
va, vb, vc, vd,
|
|
new Vector2( 0, 0 ),
|
|
new Vector2( 0, 1 ),
|
|
new Vector2( 1, 1 ),
|
|
new Vector2( 1, 0 )
|
|
);
|
|
}
|
|
|
|
public void AddQuad( Vector3 offset, float size )
|
|
{
|
|
var center = new Vector3( 0.5f, 0.5f, 0 );
|
|
|
|
/*
|
|
|
|
[-0.5, -0.5] [0.5, -0.5 ]
|
|
[-0.5, 0.5] [0.5, 0.5 ]
|
|
|
|
*/
|
|
|
|
AddQuad(
|
|
new Vector3( -0.5f, -0.5f, 0 ) * size + offset ,
|
|
new Vector3( -0.5f, 0.5f, 0 ) * size + offset ,
|
|
new Vector3( 0.5f, 0.5f, 0 ) * size + offset ,
|
|
new Vector3( 0.5f, -0.5f, 0 ) * size + offset
|
|
);
|
|
}
|
|
|
|
public void AddConvex2( Convex2 convex )
|
|
{
|
|
var points = convex.points;
|
|
var tris = points.Count - 2;
|
|
|
|
for ( int i = 0; i < tris; i++ )
|
|
{
|
|
var p0 = Math3D.XYasXZ( points[ 0 ] );
|
|
var p1 = Math3D.XYasXZ( points[ i + 1 ] );
|
|
var p2 = Math3D.XYasXZ( points[ i + 2 ] );
|
|
|
|
AddTriangle( p0, p1, p2 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public ArrayMesh GenerateMesh( Mesh.PrimitiveType type = Mesh.PrimitiveType.Triangles, ArrayMesh arrayMesh = null )
|
|
{
|
|
if ( arrayMesh == null )
|
|
{
|
|
arrayMesh = new ArrayMesh();
|
|
}
|
|
|
|
var surfaceArray = new Godot.Collections.Array();
|
|
surfaceArray.Resize( (int) Mesh.ArrayType.Max );
|
|
|
|
if ( vertices != null && vertices.Count != 0 )
|
|
{
|
|
surfaceArray[ (int) Mesh.ArrayType.Vertex ] = vertices.ToArray();
|
|
}
|
|
|
|
if ( normals != null && normals.Count != 0 )
|
|
{
|
|
surfaceArray[ (int) Mesh.ArrayType.Normal ] = normals.ToArray();
|
|
}
|
|
|
|
if ( uvs != null && uvs.Count != 0 )
|
|
{
|
|
surfaceArray[ (int) Mesh.ArrayType.TexUV ] = uvs.ToArray();
|
|
}
|
|
|
|
if ( uv2s != null && uv2s.Count != 0 )
|
|
{
|
|
surfaceArray[ (int) Mesh.ArrayType.TexUV2 ] = uv2s.ToArray();
|
|
}
|
|
|
|
if ( colors != null && colors.Count != 0 )
|
|
{
|
|
surfaceArray[ (int) Mesh.ArrayType.Color ] = colors.ToArray();
|
|
}
|
|
|
|
if ( indices != null && indices.Count != 0 )
|
|
{
|
|
surfaceArray[ (int) Mesh.ArrayType.Index ] = indices.ToArray();
|
|
}
|
|
|
|
arrayMesh.AddSurfaceFromArrays( Mesh.PrimitiveType.Triangles, surfaceArray );
|
|
|
|
return arrayMesh;
|
|
}
|
|
|
|
}
|
|
} |