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