Add Unity-compatible simplex noise semantics
This commit is contained in:
parent
102403efac
commit
cb481b4c75
5 changed files with 101 additions and 0 deletions
|
|
@ -1,5 +1,15 @@
|
|||
# Third-Party Notices
|
||||
|
||||
## 2D Simplex Noise
|
||||
|
||||
`math.simplex_noise` and `cultmath_simplex_noise` port the textureless 2D
|
||||
simplex-noise function by Ian McEwan and Ashima Arts, as distributed by Stefan
|
||||
Gustavson's `webgl-noise` project and Unity Mathematics.
|
||||
|
||||
- Copyright 2011 Ashima Arts.
|
||||
- Upstream: <https://github.com/ashima/webgl-noise>
|
||||
- License: MIT.
|
||||
|
||||
## Advanced Terrain Erosion Filter
|
||||
|
||||
`src/CultMath/AdvancedErosionFilter.cs` and
|
||||
|
|
|
|||
|
|
@ -73,6 +73,42 @@ float cultmath_smootherstep(float value)
|
|||
return value * value * value * (value * (value * 6.0 - 15.0) + 10.0);
|
||||
}
|
||||
|
||||
float2 cultmath_simplex_mod289(float2 value) { return value - floor(value * (1.0 / 289.0)) * 289.0; }
|
||||
float3 cultmath_simplex_mod289(float3 value) { return value - floor(value * (1.0 / 289.0)) * 289.0; }
|
||||
float3 cultmath_simplex_permute(float3 value) { return cultmath_simplex_mod289(((value * 34.0) + 1.0) * value); }
|
||||
|
||||
float cultmath_simplex_noise(float2 value)
|
||||
{
|
||||
const float4 c = float4(
|
||||
0.211324865405187,
|
||||
0.366025403784439,
|
||||
-0.577350269189626,
|
||||
0.024390243902439);
|
||||
float2 i = floor(value + dot(value, c.yy));
|
||||
float2 x0 = value - i + dot(i, c.xx);
|
||||
float2 i1 = x0.x > x0.y ? float2(1.0, 0.0) : float2(0.0, 1.0);
|
||||
float4 x12 = float4(x0.x + c.x - i1.x, x0.y + c.x - i1.y, x0.x + c.z, x0.y + c.z);
|
||||
|
||||
i = cultmath_simplex_mod289(i);
|
||||
float3 p = cultmath_simplex_permute(
|
||||
cultmath_simplex_permute(i.y + float3(0.0, i1.y, 1.0)) + i.x + float3(0.0, i1.x, 1.0));
|
||||
float3 m = max(0.5 - float3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);
|
||||
m *= m;
|
||||
m *= m;
|
||||
|
||||
float3 x = 2.0 * frac(p * c.w) - 1.0;
|
||||
float3 h = abs(x) - 0.5;
|
||||
float3 ox = floor(x + 0.5);
|
||||
float3 a0 = x - ox;
|
||||
m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
|
||||
|
||||
float3 g = float3(
|
||||
a0.x * x0.x + h.x * x0.y,
|
||||
a0.y * x12.x + h.y * x12.y,
|
||||
a0.z * x12.z + h.z * x12.w);
|
||||
return 130.0 * dot(m, g);
|
||||
}
|
||||
|
||||
float cultmath_lengthsq(float2 value) { return dot(value, value); }
|
||||
float cultmath_lengthsq(float3 value) { return dot(value, value); }
|
||||
float cultmath_lengthsq(float4 value) { return dot(value, value); }
|
||||
|
|
|
|||
|
|
@ -327,6 +327,50 @@ public static class math
|
|||
public static float hash(float2 value) => hash(dot(value, new float2(127.1f, 311.7f)));
|
||||
public static float hash(float3 value) => hash(dot(value, new float3(127.1f, 311.7f, 74.7f)));
|
||||
|
||||
// Ashima Arts / Ian McEwan 2D simplex noise, kept component-explicit so
|
||||
// the C# and HLSL mirrors preserve the same float32 evaluation order.
|
||||
public static float simplex_noise(float2 value)
|
||||
{
|
||||
var c = new float4(
|
||||
0.211324865405187f,
|
||||
0.366025403784439f,
|
||||
-0.577350269189626f,
|
||||
0.024390243902439f);
|
||||
var i = floor(value + dot(value, new float2(c.y, c.y)));
|
||||
var x0 = value - i + dot(i, new float2(c.x, c.x));
|
||||
var i1 = x0.x > x0.y ? new float2(1.0f, 0.0f) : new float2(0.0f, 1.0f);
|
||||
var x12 = new float4(
|
||||
x0.x + c.x - i1.x,
|
||||
x0.y + c.x - i1.y,
|
||||
x0.x + c.z,
|
||||
x0.y + c.z);
|
||||
|
||||
i = simplex_mod289(i);
|
||||
var p = simplex_permute(simplex_permute(i.y + new float3(0.0f, i1.y, 1.0f)) + i.x + new float3(0.0f, i1.x, 1.0f));
|
||||
var m = max(0.5f - new float3(
|
||||
dot(x0, x0),
|
||||
x12.x * x12.x + x12.y * x12.y,
|
||||
x12.z * x12.z + x12.w * x12.w), 0.0f);
|
||||
m = m * m;
|
||||
m = m * m;
|
||||
|
||||
var x = 2.0f * frac(p * c.w) - 1.0f;
|
||||
var h = abs(x) - 0.5f;
|
||||
var ox = floor(x + 0.5f);
|
||||
var a0 = x - ox;
|
||||
m *= 1.79284291400159f - 0.85373472095314f * (a0 * a0 + h * h);
|
||||
|
||||
var g = new float3(
|
||||
a0.x * x0.x + h.x * x0.y,
|
||||
a0.y * x12.x + h.y * x12.y,
|
||||
a0.z * x12.z + h.z * x12.w);
|
||||
return 130.0f * dot(m, g);
|
||||
}
|
||||
|
||||
private static float2 simplex_mod289(float2 value) => value - floor(value * (1.0f / 289.0f)) * 289.0f;
|
||||
private static float3 simplex_mod289(float3 value) => value - floor(value * (1.0f / 289.0f)) * 289.0f;
|
||||
private static float3 simplex_permute(float3 value) => simplex_mod289(((value * 34.0f) + 1.0f) * value);
|
||||
|
||||
public static float value_noise(float2 position)
|
||||
{
|
||||
var cell = floor(position);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ public sealed class HlslMirrorTests
|
|||
"cultmath_cubic_bezier",
|
||||
"cultmath_hash",
|
||||
"cultmath_value_noise",
|
||||
"cultmath_simplex_noise",
|
||||
"cultmath_value_noise_bicubic",
|
||||
"cultmath_value_noise_texture",
|
||||
"cultmath_value_noise_texture_bicubic",
|
||||
|
|
|
|||
|
|
@ -235,6 +235,16 @@ public sealed class MathTests
|
|||
Assert.True(bicubic > -0.25f && bicubic < 1.25f);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0.0f, 0.0f, 0.0f)]
|
||||
[InlineData(0.25f, -0.5f, -0.425866783f)]
|
||||
[InlineData(12.25f, -4.5f, 0.258312f)]
|
||||
[InlineData(536.5106f, 536.5106f, -0.6901103f)]
|
||||
public void SimplexNoiseMatchesUnityMathematics(float x, float y, float expected)
|
||||
{
|
||||
Assert.Equal(expected, math.simplex_noise(new float2(x, y)), precision: 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VoronoiBatchProducesToneMappedColors()
|
||||
{
|
||||
|
|
|
|||
Reference in a new issue