Files
Fishing2/Assets/Procedural Worlds/GeNa/Resources/Compute/Includes/GPUNoise.cginc
2026-02-28 12:43:44 +08:00

483 lines
18 KiB
HLSL

#ifndef GENA_NOISE
#define GENA_NOISE
////////////////////////////////////////////////////////////////////////////////
//Includes
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//Constants
////////////////////////////////////////////////////////////////////////////////
//
// static const uint NumThreads = 256;
// static const float PI = 3.14159265358979323846f;
// static const float DEGREES_TO_RADIANS = PI / 180.0f;
////////////////////////////////////////////////////////////////////////////////
// Noise Methods
////////////////////////////////////////////////////////////////////////////////
// The noise methods in this section have been adapted from the amazing open source turbulence
// libary by Jérémie St-Amand - check it out here https://github.com/jesta88/Turbulence-Library
//
// The licence for the noise specific methods contained in this shader are open source and
// the licence for them can be found here:
//
// https://github.com/jesta88/Turbulence-Library/blob/master/LICENSE
//
// FAST32_hash
// A very fast hashing function. Requires 32bit support.
// http://briansharpe.wordpress.com/2011/11/15/a-fast-and-simple-32bit-floating-point-hash-function/
//
// The hash formula takes the form....
// hash = mod( coord.x * coord.x * coord.y * coord.y, SOMELARGEFLOAT ) / SOMELARGEFLOAT
// We truncate and offset the domain to the most interesting part of the noise.
// SOMELARGEFLOAT should be in the range of 400.0->1000.0 and needs to be hand picked. Only some give good results.
// 3D Noise is achieved by offsetting the SOMELARGEFLOAT value by the Z coordinate
//
void FAST32_hash_2D(float2 gridcell, out float4 hash_0, out float4 hash_1) // generates 2 random numbers for each of the 4 cell corners
{
// gridcell is assumed to be an integer coordinate
const float2 OFFSET = float2(26.0, 161.0);
const float DOMAIN = 71.0;
const float2 SOMELARGEFLOATS = float2(951.135664, 642.949883);
float4 P = float4(gridcell.xy, gridcell.xy + 1.0);
P = P - floor(P * (1.0 / DOMAIN)) * DOMAIN;
P += OFFSET.xyxy;
P *= P;
P = P.xzxz * P.yyww;
hash_0 = frac(P * (1.0 / SOMELARGEFLOATS.x));
hash_1 = frac(P * (1.0 / SOMELARGEFLOATS.y));
}
//
// FAST32_hash
// A very fast hashing function. Requires 32bit support.
// http://briansharpe.wordpress.com/2011/11/15/a-fast-and-simple-32bit-floating-point-hash-function/
//
// The hash formula takes the form....
// hash = mod( coord.x * coord.x * coord.y * coord.y, SOMELARGEFLOAT ) / SOMELARGEFLOAT
// We truncate and offset the domain to the most interesting part of the noise.
// SOMELARGEFLOAT should be in the range of 400.0->1000.0 and needs to be hand picked. Only some give good results.
// 3D Noise is achieved by offsetting the SOMELARGEFLOAT value by the Z coordinate
//
float4 FAST32_hash_2D_Cell(float2 gridcell) // generates 4 different random numbers for the single given cell point
{
// gridcell is assumed to be an integer coordinate
const float2 OFFSET = float2(26.0, 161.0);
const float DOMAIN = 71.0;
const float4 SOMELARGEFLOATS = float4(951.135664, 642.949883, 803.202459, 986.973274);
float2 P = gridcell - floor(gridcell * (1.0 / DOMAIN)) * DOMAIN;
P += OFFSET.xy;
P *= P;
return frac((P.x * P.y) * (1.0 / SOMELARGEFLOATS.xyzw));
}
//
// SimplexPerlin2D ( simplex gradient noise )
// Perlin noise over a simplex (triangular) grid
// Return value range of -1.0->1.0
// http://briansharpe.files.wordpress.com/2012/01/simplexperlinsample.jpg
//
// Implementation originally based off Stefan Gustavson's and Ian McEwan's work at...
// http://github.com/ashima/webgl-noise
//
float SimplexPerlin2D(float2 P)
{
// simplex math constants
const float SKEWFACTOR = 0.36602540378443864676372317075294; // 0.5*(sqrt(3.0)-1.0)
const float UNSKEWFACTOR = 0.21132486540518711774542560974902; // (3.0-sqrt(3.0))/6.0
const float SIMPLEX_TRI_HEIGHT = 0.70710678118654752440084436210485; // sqrt( 0.5 ) height of simplex triangle
const float3 SIMPLEX_POINTS = float3(1.0 - UNSKEWFACTOR, -UNSKEWFACTOR, 1.0 - 2.0 * UNSKEWFACTOR); // vertex info for simplex triangle
// establish our grid cell.
P *= SIMPLEX_TRI_HEIGHT; // scale space so we can have an approx feature size of 1.0 ( optional )
const float2 Pi = floor(P + dot(P, float2(SKEWFACTOR, SKEWFACTOR)));
// calculate the hash.
float4 hash_x, hash_y;
FAST32_hash_2D(Pi, hash_x, hash_y);
// establish vectors to the 3 corners of our simplex triangle
float2 v0 = Pi - dot(Pi, float2(UNSKEWFACTOR, UNSKEWFACTOR)) - P;
float4 v1pos_v1hash = (v0.x < v0.y) ? float4(SIMPLEX_POINTS.xy, hash_x.y, hash_y.y) : float4(SIMPLEX_POINTS.yx, hash_x.z, hash_y.z);
float4 v12 = float4(v1pos_v1hash.xy, SIMPLEX_POINTS.zz) + v0.xyxy;
// calculate the dotproduct of our 3 corner vectors with 3 random normalized vectors
const float3 grad_x = float3(hash_x.x, v1pos_v1hash.z, hash_x.w) - 0.49999;
const float3 grad_y = float3(hash_y.x, v1pos_v1hash.w, hash_y.w) - 0.49999;
const float3 grad_results = rsqrt(grad_x * grad_x + grad_y * grad_y) * (grad_x * float3(v0.x, v12.xz) + grad_y * float3(v0.y, v12.yw));
// Normalization factor to scale the final result to a strict 1.0->-1.0 range
// x = ( sqrt( 0.5 )/sqrt( 0.75 ) ) * 0.5
// NF = 1.0 / ( x * ( ( 0.5 ? x*x ) ^ 4 ) * 2.0 )
// http://briansharpe.wordpress.com/2012/01/13/simplex-noise/#comment-36
const float FINAL_NORMALIZATION = 99.204334582718712976990005025589;
// evaluate the surflet, sum and return
float3 m = float3(v0.x, v12.xz) * float3(v0.x, v12.xz) + float3(v0.y, v12.yw) * float3(v0.y, v12.yw);
m = max(0.5 - m, 0.0); // The 0.5 here is SIMPLEX_TRI_HEIGHT^2
m = m * m;
m = m * m;
return dot(m, grad_results) * FINAL_NORMALIZATION;
}
//
// SimplexPerlin2D_Deriv
// SimplexPerlin2D noise with derivatives
// returns float3( value, xderiv, yderiv )
//
float3 SimplexPerlin2D_Deriv(float2 P)
{
// simplex math constants
const float SKEWFACTOR = 0.36602540378443864676372317075294; // 0.5*(sqrt(3.0)-1.0)
const float UNSKEWFACTOR = 0.21132486540518711774542560974902; // (3.0-sqrt(3.0))/6.0
const float SIMPLEX_TRI_HEIGHT = 0.70710678118654752440084436210485; // sqrt( 0.5 ) height of simplex triangle
const float3 SIMPLEX_POINTS = float3(1.0 - UNSKEWFACTOR, -UNSKEWFACTOR, 1.0 - 2.0 * UNSKEWFACTOR); // vertex info for simplex triangle
// establish our grid cell.
P *= SIMPLEX_TRI_HEIGHT; // scale space so we can have an approx feature size of 1.0 ( optional )
const float2 Pi = floor(P + dot(P, float2(SKEWFACTOR, SKEWFACTOR)));
// calculate the hash.
float4 hash_x, hash_y;
FAST32_hash_2D(Pi, hash_x, hash_y);
// establish vectors to the 3 corners of our simplex triangle
float2 v0 = Pi - dot(Pi, float2(UNSKEWFACTOR, UNSKEWFACTOR)) - P;
float4 v1pos_v1hash = (v0.x < v0.y) ? float4(SIMPLEX_POINTS.xy, hash_x.y, hash_y.y) : float4(SIMPLEX_POINTS.yx, hash_x.z, hash_y.z);
float4 v12 = float4(v1pos_v1hash.xy, SIMPLEX_POINTS.zz) + v0.xyxy;
// calculate the dotproduct of our 3 corner vectors with 3 random normalized vectors
float3 grad_x = float3(hash_x.x, v1pos_v1hash.z, hash_x.w) - 0.49999;
float3 grad_y = float3(hash_y.x, v1pos_v1hash.w, hash_y.w) - 0.49999;
const float3 norm = rsqrt(grad_x * grad_x + grad_y * grad_y);
grad_x *= norm;
grad_y *= norm;
const float3 grad_results = grad_x * float3(v0.x, v12.xz) + grad_y * float3(v0.y, v12.yw);
// evaluate the surflet
float3 m = float3(v0.x, v12.xz) * float3(v0.x, v12.xz) + float3(v0.y, v12.yw) * float3(v0.y, v12.yw);
m = max(0.5 - m, 0.0); // The 0.5 here is SIMPLEX_TRI_HEIGHT^2
const float3 m2 = m * m;
const float3 m4 = m2 * m2;
// calc the deriv
const float3 temp = 8.0 * m2 * m * grad_results;
float xderiv = dot(temp, float3(v0.x, v12.xz)) - dot(m4, grad_x);
float yderiv = dot(temp, float3(v0.y, v12.yw)) - dot(m4, grad_y);
const float FINAL_NORMALIZATION = 99.204334582718712976990005025589; // scales the final result to a strict 1.0->-1.0 range
// sum the surflets and return all results combined in a float3
return float3(dot(m4, grad_results), xderiv, yderiv) * FINAL_NORMALIZATION;
}
float Cellular2D(float2 xy, int cellType, int distanceFunction)
{
const int xi = int(floor(xy.x));
const int yi = int(floor(xy.y));
const float xf = xy.x - float(xi);
const float yf = xy.y - float(yi);
float dist1 = 9999999.0;
float dist2 = 9999999.0;
float dist3 = 9999999.0;
float dist4 = 9999999.0;
for (int y = -1; y <= 1; y++)
{
for (int x = -1; x <= 1; x++)
{
float2 cell = FAST32_hash_2D_Cell(float2(xi + x, yi + y)).xy;
cell.x += (float(x) - xf);
cell.y += (float(y) - yf);
float dist = 0.0;
if (distanceFunction <= 1)
{
dist = sqrt(dot(cell, cell));
}
else if (distanceFunction > 1 && distanceFunction <= 2)
{
dist = dot(cell, cell);
}
else if (distanceFunction > 2 && distanceFunction <= 3)
{
dist = abs(cell.x) + abs(cell.y);
dist *= dist;
}
else if (distanceFunction > 3 && distanceFunction <= 4)
{
dist = max(abs(cell.x), abs(cell.y));
dist *= dist;
}
else if (distanceFunction > 4 && distanceFunction <= 5)
{
dist = dot(cell, cell) + cell.x * cell.y;
}
else if (distanceFunction > 5 && distanceFunction <= 6)
{
dist = pow(abs(cell.x * cell.x * cell.x * cell.x + cell.y * cell.y * cell.y * cell.y), 0.25);
}
else if (distanceFunction > 6 && distanceFunction <= 7)
{
dist = sqrt(abs(cell.x)) + sqrt(abs(cell.y));
dist *= dist;
}
if (dist < dist1)
{
dist4 = dist3;
dist3 = dist2;
dist2 = dist1;
dist1 = dist;
}
else if (dist < dist2)
{
dist4 = dist3;
dist3 = dist2;
dist2 = dist;
}
else if (dist < dist3)
{
dist4 = dist3;
dist3 = dist;
}
else if (dist < dist4)
{
dist4 = dist;
}
}
}
float result;
if (cellType <= 1) // F1
result = dist1; // scale return value from 0.0->1.333333 to 0.0->1.0 (2/3)^2 * 3 == (12/9) == 1.333333
else if (cellType > 1 && cellType <= 2) // F2
result = dist2;
else if (cellType > 2 && cellType <= 3) // F3
result = dist3;
else if (cellType > 3 && cellType <= 4) // F4
result = dist4;
else if (cellType > 4 && cellType <= 5) // F2 - F1
result = dist2 - dist1;
else if (cellType > 5 && cellType <= 6) // F3 - F2
result = dist3 - dist2;
else if (cellType > 6 && cellType <= 7) // F1 + F2/2
result = dist1 + dist2 / 2.0;
else if (cellType > 7 && cellType <= 8) // F1 * F2
result = dist1 * dist2;
else if (cellType > 8 && cellType <= 9) // Crackle
result = max(1.0, 10 * (dist2 - dist1));
else
result = dist1;
return result;
}
//Get simplex
float SimplexNormal(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence)
{
float sum = 0;
for (int i = 0; i < octaves; i++)
{
const float h = SimplexPerlin2D((p + offset) * frequency);
sum += h * amplitude;
frequency *= lacunarity;
amplitude *= persistence;
}
return sum;
}
//Get multi fractal simplex noise
float SimplexMulti(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence, float ridgeOffset)
{
float result = SimplexNormal(p, 3, offset, frequency, amplitude, lacunarity, persistence);
if (result > ridgeOffset)
{
result = lerp(result, SimplexNormal(p, octaves, offset, frequency, amplitude, lacunarity, persistence), result - ridgeOffset);
}
return result;
}
//Get simplex billow
float SimplexBillowed(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence)
{
float sum = 0;
for (int i = 0; i < octaves; i++)
{
const float h = abs(SimplexPerlin2D((p + offset) * frequency));
sum += h * amplitude;
frequency *= lacunarity;
amplitude *= persistence;
}
return sum;
}
//Get simplex ridged
float SimplexRidged(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence, float ridgeOffset)
{
float sum = 0;
for (int i = 0; i < octaves; i++)
{
const float h = 0.5 * (ridgeOffset - abs(4 * SimplexPerlin2D((p + offset) * frequency)));
sum += h * amplitude;
frequency *= lacunarity;
amplitude *= persistence;
}
return sum;
}
//Get simplex derived IQ
float SimplexDerivedIQ(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence)
{
float sum = 0;
float2 dsum = float2(0.0, 0.0);
for (int i = 0; i < octaves; i++)
{
float3 n = SimplexPerlin2D_Deriv((p + offset) * frequency);
dsum += n.yz;
sum += amplitude * n.x / (1 + dot(dsum, dsum));
frequency *= lacunarity;
amplitude *= persistence;
}
return sum;
}
//Get simplex derived swiss
float SimplexDerivedSwiss(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence, float warp, float ridgeOffset)
{
float sum = 0.0;
float2 dsum = float2(0.0, 0.0);
for (int i = 0; i < octaves; i++)
{
float3 n = 0.5 * (0 + (ridgeOffset - abs(SimplexPerlin2D_Deriv((p + offset + warp * dsum) * frequency))));
sum += amplitude * n.x;
dsum += amplitude * n.yz * -n.x;
frequency *= lacunarity;
amplitude *= persistence * saturate(sum);
}
return sum;
}
//Simpelx derived Jordan
float SimplexDerivedJordan(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence, float warp0, float warp, float damp0, float damp, float damp_scale)
{
float3 n = SimplexPerlin2D_Deriv((p + offset) * frequency);
float3 n2 = n * n.x;
float sum = n2.x;
float2 dsum_warp = warp0 * n2.yz;
float2 dsum_damp = damp0 * n2.yz;
float damped_amp = amplitude * persistence;
for (int i = 0; i < octaves; i++)
{
n = SimplexPerlin2D_Deriv((p + offset) * frequency + dsum_warp.xy);
n2 = n * n.x;
sum += damped_amp * n2.x;
dsum_warp += warp * n2.yz;
dsum_damp += damp * n2.yz;
frequency *= lacunarity;
amplitude *= persistence * saturate(sum);
damped_amp = amplitude * (1 - damp_scale / (1 + dot(dsum_damp, dsum_damp)));
}
return sum;
}
//Get cell noise
float CellNormal(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence, int cellType, int distanceFunction)
{
float sum = 0;
for (int i = 0; i < octaves; i++)
{
const float h = Cellular2D((p + offset) * frequency, cellType, distanceFunction);
sum += h * amplitude;
frequency *= lacunarity;
amplitude *= persistence;
}
return sum;
}
////////////////////////////////////////////////////////////////////////////////
// Utility Methods
////////////////////////////////////////////////////////////////////////////////
//Get the distance beweent two points
float GetDistance(float2 point1, float2 point2)
{
return sqrt(pow(point2.y - point1.y, 2) + pow(point2.x - point1.x, 2));
}
// Convert a 1D address into a 2D address assuming the dimensions supplied
uint2 Translate1DTo2D(uint address1D, uint dimensions)
{
//Calculate location
uint y = address1D / dimensions;
uint x = address1D - (y * dimensions);
//Return
return uint2(x, y);
}
// Convert a 2D normalised address to a 1D non normalised address
uint Translate2DTo1DActual(float2 address2D, float dimensions)
{
const uint x = address2D.x * (dimensions - 1.0);
const uint y = address2D.y * (dimensions - 1.0);
return (y * dimensions) + x;
}
// Convert a standard 2d address to a 1d address
uint Translate2DTo1D(uint x, uint y, float dimensions)
{
return (y * dimensions) + x;
}
float GetNoise(float2 position)
{
float result = 0.0f;
if (_NoisemapEnabled)
{
const float2 address = position + _NoisemapSeed / 100.0f;
switch (_NoisemapType)
{
case 0: // Perlin
result = SimplexNormal(address, _NoisemapOctaves, _NoisemapOffset, _NoisemapFrequency, _NoisemapAmplitude, _NoisemapLacunarity, _NoisemapPersistence);
break;
case 1: // Billow
result = SimplexBillowed(address, _NoisemapOctaves, _NoisemapOffset, _NoisemapFrequency, _NoisemapAmplitude, _NoisemapLacunarity, _NoisemapPersistence);
break;
case 2: // Ridged
result = SimplexRidged(address, _NoisemapOctaves, _NoisemapOffset, _NoisemapFrequency, _NoisemapAmplitude, _NoisemapLacunarity, _NoisemapPersistence, _NoisemapRidgedOffset);
break;
case 3: // IQ
result = SimplexDerivedIQ(address, _NoisemapOctaves, _NoisemapOffset, _NoisemapFrequency, _NoisemapAmplitude, _NoisemapLacunarity, _NoisemapPersistence);
break;
case 4: // Swiss
result = SimplexDerivedSwiss(address, _NoisemapOctaves, _NoisemapOffset, _NoisemapFrequency, _NoisemapAmplitude, _NoisemapLacunarity, _NoisemapPersistence, _NoisemapWarp, _NoisemapRidgedOffset);
break;
case 5: // Jordan
result = SimplexDerivedJordan(address, _NoisemapOctaves, _NoisemapOffset, _NoisemapFrequency, _NoisemapAmplitude, _NoisemapLacunarity, _NoisemapPersistence, _NoisemapWarp0, _NoisemapWarp, _NoisemapDamp0, _NoisemapDamp, _NoisemapDampScale);
break;
default:
result = 0.0f;
break;
}
}
return result;
}
void GetNoise_float(float2 position, out float o_output)
{
if (_NoisemapEnabled)
{
o_output = (GetNoise(position) * 2.0f - 1.0f) * _NoisemapStrength;
}
else
{
o_output = 0.0f;
}
}
#endif