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 materials; public List albedoTexture; public List albedo; public float densityResolution = 0.2f; List 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 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(); 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(); var normals = new List(); var uvs = new List(); 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(); 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 p, List u, List 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 ); } } } } }