141 lines
3.2 KiB
C#
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;
|
|
}
|
|
}
|
|
} |