rj-action-library/Runtime/Procedural/HeightMap/HeightMapData.cs

141 lines
3.2 KiB
C#

using Godot;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Rokojori
{
public class HeightMapData
{
int width;
int height;
float[] data;
public static HeightMapData Create( int w, int h, float[] data = null)
{
var hmd = new HeightMapData();
hmd.width = w;
hmd.height = h;
hmd.data = data == null ? new float[ w * h ] : data;
return hmd;
}
public float Get( int x, int y )
{
x = Mathf.Clamp( x, 0, width - 1 );
y = Mathf.Clamp( y, 0, height - 1 );
return data[ x + y * width ];
}
public float GetLerped( float x, float y )
{
var x0 = Mathf.FloorToInt( x );
var x1 = x0 + 1;
var y0 = Mathf.FloorToInt( y );
var y1 = y0 + 1;
var xL = x - x0;
var yL = y - y0;
// xy xy
// 00 10
// 10 11
var upValue = Mathf.Lerp( Get( x0, y0 ), Get( x1, y0 ), xL );
var downValue = Mathf.Lerp( Get( x0, y1 ), Get( x1, y1 ), xL );
return Mathf.Lerp( upValue, downValue, yL );
}
public void Set( int x, int y, float value )
{
if ( x < 0 || y < 0 || x >= width || y >= height )
{
return;
}
data[ x + y * width ] = value;
}
public Vector3 GetNormal( int x, int y, float strength = 8f )
{
var tl = Get( x-1, y-1 );
var l = Get( x-1, y );
var bl = Get( x-1, y+1) ;
var t = Get( x, y-1 );
var b = Get( x, y+1 );
var tr = Get( x+1, y-1 );
var r = Get( x+1, y );
var br = Get( x+1, y+1 );
var nx = ( tr + 2.0f * r + br ) - ( tl + 2.0f * l + bl );
var nz = ( bl + 2.0f * b + br ) - ( tl + 2.0f * t + tr );
var ny = 1.0f / strength;
return -new Vector3( nx, ny, nz ).Normalized();
}
public Vector3 GetNormal( float x, float y, float strength = 1f )
{
return GetNormal( (int)x, (int)y, strength );
}
public MeshGeometry GenerateMeshGeometry( Vector3 scale )
{
var func = ( Vector2 uv )=>
{
var p = new Pose();
var x = uv.X * width;
var z = uv.Y * height;
var y = GetLerped( x, z );
p.position = new Vector3( x * scale.X, y * scale.Y, z * scale.Z );
p.up = GetNormal( x, z );
return p;
};
return MeshGeometry.CreateFromUVFunction( func, width - 1, height - 1 );
}
public HeightMapData CreateLowerResolution( float averageVsMaxFilter = 0.5f )
{
var lw = width/2;
var lh = height/2;
var lower = Create( lw, lh );
for ( int i = 0; i < lw; i++ )
{
for ( int j = 0; j < lh; j++ )
{
var x0 = i * 2;
var x1 = x0 + 1;
var y0 = j * 2;
var y1 = y0 +1;
var s0 = Get( x0, y0 );
var s1 = Get( x1, y0 );
var s2 = Get( x0, y1 );
var s3 = Get( x1, y1 );
var maxValue = MathX.Max( s0, s1, s2, s3 );
var avgValue = (s0 + s1 + s2 + s3 ) / 4f;
var value = Mathf.Lerp( avgValue, maxValue, averageVsMaxFilter );
lower.Set( i, j, value );
}
}
return lower;
}
}
}