406 lines
9.7 KiB
C#
406 lines
9.7 KiB
C#
![]() |
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using Godot;
|
||
|
using System;
|
||
|
|
||
|
using System.Threading.Tasks;
|
||
|
|
||
|
namespace Rokojori.PointClouds
|
||
|
{
|
||
|
|
||
|
public class PointCloudSampler
|
||
|
{
|
||
|
public enum SampleMode
|
||
|
{
|
||
|
Center,
|
||
|
Vertices,
|
||
|
CenterAndVertices,
|
||
|
Density
|
||
|
}
|
||
|
|
||
|
public List<Material> materials;
|
||
|
public List<Texture2DPropertyName> albedoTexture;
|
||
|
public List<ColorPropertyName> albedo;
|
||
|
public float densityResolution = 0.2f;
|
||
|
|
||
|
List<Image> albedoTextureImages;
|
||
|
|
||
|
SampleMode mode;
|
||
|
|
||
|
ArrayMesh mesh;
|
||
|
Node worker;
|
||
|
|
||
|
PointCloud pointCloud;
|
||
|
|
||
|
|
||
|
|
||
|
public PointCloud SampleFromMeshSync( SampleMode sampleMode, ArrayMesh mesh, Node worker )
|
||
|
{
|
||
|
this.mode = sampleMode;
|
||
|
this.mesh = mesh;
|
||
|
this.worker = worker;
|
||
|
|
||
|
pointCloud = new PointCloud();
|
||
|
|
||
|
GrabTextureImages();
|
||
|
|
||
|
for ( int i = 0; i < mesh.GetSurfaceCount(); i++ )
|
||
|
{
|
||
|
SampleSurfaceSync( mesh, i );
|
||
|
}
|
||
|
|
||
|
return pointCloud;
|
||
|
|
||
|
}
|
||
|
|
||
|
public async Task<PointCloud> SampleFromMesh( SampleMode sampleMode, ArrayMesh mesh, Node worker )
|
||
|
{
|
||
|
|
||
|
this.mode = sampleMode;
|
||
|
this.mesh = mesh;
|
||
|
this.worker = worker;
|
||
|
|
||
|
pointCloud = new PointCloud();
|
||
|
|
||
|
try
|
||
|
{
|
||
|
|
||
|
|
||
|
GrabTextureImages();
|
||
|
|
||
|
for ( int i = 0; i < mesh.GetSurfaceCount(); i++ )
|
||
|
{
|
||
|
await SampleSurface( mesh, i );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
catch ( System.Exception e )
|
||
|
{
|
||
|
worker.LogError( e );
|
||
|
}
|
||
|
|
||
|
return pointCloud;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void GrabTextureImages()
|
||
|
{
|
||
|
var index = -1;
|
||
|
|
||
|
albedoTextureImages = new List<Image>();
|
||
|
|
||
|
albedoTexture.ForEach(
|
||
|
( at )=>
|
||
|
{
|
||
|
index++;
|
||
|
|
||
|
if ( at == null )
|
||
|
{
|
||
|
albedoTextureImages.Add( null );
|
||
|
}
|
||
|
|
||
|
var material = materials[ index ];
|
||
|
var texture = at.Get( material );
|
||
|
|
||
|
if ( texture == null )
|
||
|
{
|
||
|
albedoTextureImages.Add( null );
|
||
|
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
var image = texture.GetImage();
|
||
|
|
||
|
albedoTextureImages.Add( image );
|
||
|
}
|
||
|
);
|
||
|
|
||
|
// worker.LogInfo( "Added image:", albedoTextureImages.Count );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
public void SampleSurfaceSync( ArrayMesh mesh, int surface )
|
||
|
{
|
||
|
if ( SampleMode.Density == mode )
|
||
|
{
|
||
|
SampleDensitySync( mesh, surface );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SampleSimpleSync( mesh, surface );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void SampleDensitySync( ArrayMesh mesh, int surface )
|
||
|
{
|
||
|
var mdt = new MeshDataTool();
|
||
|
mdt.CreateFromSurface( mesh, surface );
|
||
|
|
||
|
var nullTriangles = 0;
|
||
|
var numFaces = mdt.GetFaceCount();
|
||
|
var subDivs = 0;
|
||
|
|
||
|
|
||
|
for ( int i = 0; i < mdt.GetFaceCount(); i++ )
|
||
|
{
|
||
|
// time = await Async.WaitIfExceeded( time, worker );
|
||
|
|
||
|
var positions = new List<Vector3>();
|
||
|
var normals = new List<Vector3>();
|
||
|
var uvs = new List<Vector2>();
|
||
|
|
||
|
for ( int j = 0; j < 3; j++ )
|
||
|
{
|
||
|
var index = mdt.GetFaceVertex( i, j );
|
||
|
|
||
|
var p = mdt.GetVertex( index );
|
||
|
var uv = mdt.GetVertexUV( index );
|
||
|
var n = mdt.GetVertexNormal( index );
|
||
|
|
||
|
positions.Add( p );
|
||
|
uvs.Add( uv );
|
||
|
normals.Add( n );
|
||
|
}
|
||
|
|
||
|
var triangle = Triangle3.CreateFrom( positions );
|
||
|
|
||
|
AddPoints( positions, uvs, normals );
|
||
|
|
||
|
var minArea = densityResolution;
|
||
|
|
||
|
var points = new List<Vector3>();
|
||
|
triangle.GetSubdivisionPoints( points, minArea );
|
||
|
|
||
|
|
||
|
// worker.LogInfo( triangle.area, points.Count );
|
||
|
|
||
|
|
||
|
points.ForEach(
|
||
|
( p )=>
|
||
|
{
|
||
|
var uv = (Vector2) triangle.Lerp( p, uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] );
|
||
|
var n = (Vector3) triangle.Lerp( p, normals[ 0 ], normals[ 1 ], normals[ 2 ] );
|
||
|
|
||
|
AddPoint( p, uv, n );
|
||
|
subDivs ++;
|
||
|
}
|
||
|
);
|
||
|
|
||
|
// if ( triangle.area > minArea || triangle.longestEdgeLength > densityResolution )
|
||
|
// {
|
||
|
// worker.LogInfo( area );
|
||
|
// subDivs++;
|
||
|
// }
|
||
|
|
||
|
// triangle = triangle.Shrink( densityResolution );
|
||
|
|
||
|
// if ( triangle == null )
|
||
|
// {
|
||
|
// nullTriangles++;
|
||
|
// }
|
||
|
|
||
|
|
||
|
// var maxIterations = 1000;
|
||
|
// var iteration = 0;
|
||
|
|
||
|
// while ( iteration < maxIterations && triangle != null && ( triangle.area > minArea || triangle.longestEdgeLength > densityResolution ) )
|
||
|
// {
|
||
|
// var newUVs = positions.Map( p => (Vector2) triangle.Lerp( p, uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] ) );
|
||
|
// var newNormals = positions.Map( p => (Vector3) triangle.Lerp( p, normals[ 0 ], normals[ 1 ], normals[ 2 ] ) );
|
||
|
|
||
|
// positions = triangle.points;
|
||
|
// uvs = newUVs;
|
||
|
// normals = newNormals;
|
||
|
|
||
|
// AddPoints( positions, uvs, normals );
|
||
|
|
||
|
// triangle = triangle.Shrink( densityResolution );
|
||
|
|
||
|
// iteration ++;
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
worker.LogInfo( "Tris:", numFaces, "Nulls:", nullTriangles, "Subs:", subDivs );
|
||
|
}
|
||
|
|
||
|
void AddPoints( List<Vector3> p, List<Vector2> u, List<Vector3> n )
|
||
|
{
|
||
|
for ( int i = 0; i < p.Count; i++ )
|
||
|
{
|
||
|
AddPoint( p[ i ], u[ i ], n[ i ] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AddPoint( Vector3 p, Vector2 u, Vector3 n )
|
||
|
{
|
||
|
var point = new Point();
|
||
|
point.color = Colors.White;
|
||
|
point.position = p;
|
||
|
point.normal = n;
|
||
|
point.uv = u;
|
||
|
pointCloud.points.Add( point );
|
||
|
}
|
||
|
|
||
|
public async Task SampleSurface( ArrayMesh mesh, int surface )
|
||
|
{
|
||
|
await SampleSimple( mesh, surface );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void SampleSimpleSync( ArrayMesh mesh, int surface )
|
||
|
{
|
||
|
var mdt = new MeshDataTool();
|
||
|
mdt.CreateFromSurface( mesh, surface );
|
||
|
|
||
|
|
||
|
var sampleVertices = SampleMode.Vertices == mode || SampleMode.CenterAndVertices == mode;
|
||
|
var sampleCenter = SampleMode.Center == mode || SampleMode.CenterAndVertices == mode;
|
||
|
|
||
|
for ( int i = 0; i < mdt.GetFaceCount(); i++ )
|
||
|
{
|
||
|
// time = await Async.WaitIfExceeded( time, worker );
|
||
|
|
||
|
var center = new Vector3( 0, 0, 0 );
|
||
|
var centerColor = new Vector4( 0, 0, 0, 0 );
|
||
|
var centerNormal = new Vector3( 0, 0, 0 );
|
||
|
var centerUV = new Vector2( 0, 0 );
|
||
|
|
||
|
for ( int j = 0; j < 3; j++ )
|
||
|
{
|
||
|
var index = mdt.GetFaceVertex( i, j );
|
||
|
|
||
|
var p = mdt.GetVertex( index );
|
||
|
var uv = mdt.GetVertexUV( index );
|
||
|
var n = mdt.GetVertexNormal( index );
|
||
|
var color = Colors.White;
|
||
|
|
||
|
var image = albedoTextureImages[ surface ];
|
||
|
|
||
|
if ( image != null )
|
||
|
{
|
||
|
color = image.Sample( uv, ColorX.EdgeMode.Repeat );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
center += p;
|
||
|
centerColor += color.ToVector4();
|
||
|
centerNormal += n;
|
||
|
centerUV += uv;
|
||
|
|
||
|
if ( sampleVertices )
|
||
|
{
|
||
|
var point = new Point();
|
||
|
point.color = color;
|
||
|
point.position = p;
|
||
|
point.normal = n;
|
||
|
point.uv = uv;
|
||
|
pointCloud.points.Add( point );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( sampleCenter )
|
||
|
{
|
||
|
var point = new Point();
|
||
|
point.color = ( centerColor / 3.0f ).ToColor();
|
||
|
point.position = center / 3.0f;
|
||
|
point.normal = centerNormal / 3.0f;
|
||
|
point.uv = centerUV / 3.0f;
|
||
|
pointCloud.points.Add( point );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async Task SampleSimple( ArrayMesh mesh, int surface )
|
||
|
{
|
||
|
var mdt = new MeshDataTool();
|
||
|
mdt.CreateFromSurface( mesh, surface );
|
||
|
|
||
|
|
||
|
var sampleVertices = SampleMode.Vertices == mode || SampleMode.CenterAndVertices == mode;
|
||
|
var sampleCenter = SampleMode.Center == mode || SampleMode.CenterAndVertices == mode;
|
||
|
|
||
|
var time = Async.StartTimer();
|
||
|
|
||
|
var faces = mdt.GetFaceCount();
|
||
|
|
||
|
for ( int i = 0; i < faces; i++ )
|
||
|
{
|
||
|
time = await Async.WaitIfExceeded( time, worker );
|
||
|
|
||
|
if ( i % 10000 == 0 )
|
||
|
{
|
||
|
worker.LogInfo( "Tris:", i + "/" + faces, RegexUtility._FFF( ( 100f * i ) / (float)faces ) );
|
||
|
}
|
||
|
|
||
|
var center = new Vector3( 0, 0, 0 );
|
||
|
var centerColor = new Vector4( 0, 0, 0, 0 );
|
||
|
var centerNormal = new Vector3( 0, 0, 0 );
|
||
|
var centerUV = new Vector2( 0, 0 );
|
||
|
|
||
|
for ( int j = 0; j < 3; j++ )
|
||
|
{
|
||
|
var index = mdt.GetFaceVertex( i, j );
|
||
|
|
||
|
var p = mdt.GetVertex( index );
|
||
|
var uv = mdt.GetVertexUV( index );
|
||
|
var n = mdt.GetVertexNormal( index );
|
||
|
var color = Colors.White;
|
||
|
|
||
|
var image = albedoTextureImages[ surface ];
|
||
|
|
||
|
if ( image != null )
|
||
|
{
|
||
|
color = image.Sample( uv, ColorX.EdgeMode.Repeat );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
center += p;
|
||
|
centerColor += color.ToVector4();
|
||
|
centerNormal += n;
|
||
|
centerUV += uv;
|
||
|
|
||
|
if ( sampleVertices )
|
||
|
{
|
||
|
var point = new Point();
|
||
|
point.color = color;
|
||
|
point.position = p;
|
||
|
point.normal = n;
|
||
|
point.uv = uv;
|
||
|
pointCloud.points.Add( point );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( sampleCenter )
|
||
|
{
|
||
|
var point = new Point();
|
||
|
point.color = ( centerColor / 3.0f ).ToColor();
|
||
|
point.position = center / 3.0f;
|
||
|
point.normal = centerNormal / 3.0f;
|
||
|
point.uv = centerUV / 3.0f;
|
||
|
pointCloud.points.Add( point );
|
||
|
}
|
||
|
|
||
|
if ( i == 0 )
|
||
|
{
|
||
|
pointCloud.boundingBox = Box3.Create( center, center );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pointCloud.boundingBox.IncludePoint( center );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|