rj-action-library/Runtime/LOD/PointClouds/PointCloudSampler.cs

406 lines
9.7 KiB
C#
Raw Normal View History

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 );
}
}
}
}
}