Skip to content

Commit 5e78ef6

Browse files
authored
Noise optimize (#29)
* double -> float * Optimize noise * Fix
1 parent 0907e26 commit 5e78ef6

File tree

5 files changed

+222
-77
lines changed

5 files changed

+222
-77
lines changed

src/MineCase.Algorithm/Noise/INoise.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ namespace MineCase.Algorithm.Noise
77
{
88
public interface INoise
99
{
10-
double Noise(double x, double y, double z);
10+
float Noise(float x, float y, float z);
1111

12-
void Noise(double[,,] noise, Vector3 offset, Vector3 scale);
12+
void Noise(float[,,] noise, Vector3 offset, Vector3 scale);
13+
14+
void AddNoise(float[,,] noise, Vector3 offset, Vector3 scale, float noiseScale);
1315
}
1416
}

src/MineCase.Algorithm/Noise/NoiseBase.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Numerics;
34
using System.Text;
45

56
namespace MineCase.Algorithm.Noise
67
{
7-
public class OctavedNoise<TNoise> : NoiseBase, INoise
8+
public class OctavedNoise<TNoise>
89
where TNoise : INoise
910
{
1011
private readonly TNoise _innerNoise;
1112
private readonly int _octaves;
12-
private readonly double _persistence;
13+
private readonly float _persistence;
1314

14-
public OctavedNoise(TNoise innerNoise, int octaves, double persistence)
15+
public OctavedNoise(TNoise innerNoise, int octaves, float persistence)
1516
{
1617
_innerNoise = innerNoise;
1718
_octaves = octaves;
1819
_persistence = persistence;
1920
}
2021

21-
public override double Noise(double x, double y, double z)
22+
public float Noise(float x, float y, float z)
2223
{
2324
double total = 0;
24-
double frequency = 1;
25+
int frequency = 1;
2526
double amplitude = 1;
2627
double maxValue = 0;
2728

@@ -33,7 +34,35 @@ public override double Noise(double x, double y, double z)
3334
frequency *= 2;
3435
}
3536

36-
return total / maxValue;
37+
return (float)(total / maxValue);
38+
}
39+
40+
public void Noise(float[,,] noise, Vector3 offset, Vector3 scale)
41+
{
42+
Array.Clear(noise, 0, noise.Length);
43+
int frequency = 1;
44+
double amplitude = 1;
45+
double maxValue = 0;
46+
47+
for (int i = 0; i < _octaves; i++)
48+
{
49+
_innerNoise.AddNoise(noise, offset * frequency, scale * frequency, (float)amplitude);
50+
maxValue += amplitude;
51+
amplitude *= _persistence;
52+
frequency *= 2;
53+
}
54+
55+
var xExtent = noise.GetUpperBound(0) + 1;
56+
var yExtent = noise.GetUpperBound(1) + 1;
57+
var zExtent = noise.GetUpperBound(2) + 1;
58+
for (int x = 0; x < xExtent; x++)
59+
{
60+
for (int y = 0; y < yExtent; y++)
61+
{
62+
for (int z = 0; z < zExtent; z++)
63+
noise[x, y, z] /= (float)maxValue;
64+
}
65+
}
3766
}
3867
}
3968
}

src/MineCase.Algorithm/Noise/PerlinNoise.cs

Lines changed: 154 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace MineCase.Algorithm.Noise
88
/// <summary>
99
/// Implementation for Improved Perlin Noise (http://mrl.nyu.edu/~perlin/noise/)
1010
/// </summary>
11-
public class PerlinNoise : NoiseBase, INoise
11+
public class PerlinNoise : INoise
1212
{
1313
/// <summary>
1414
/// Permutation
@@ -26,7 +26,7 @@ public PerlinNoise(int seed)
2626
_p[i + 256] = _p[i] = random.Next(0, 256);
2727
}
2828

29-
public override double Noise(double x, double y, double z)
29+
public float Noise(float x, float y, float z)
3030
{
3131
var xcoord = Split(x);
3232
var ycoord = Split(y);
@@ -36,54 +36,174 @@ public override double Noise(double x, double y, double z)
3636
var v = Fade(ycoord.remainder);
3737
var w = Fade(zcoord.remainder);
3838

39-
int aaa, aba, aab, abb, baa, bba, bab, bbb;
40-
aaa = _p[_p[_p[xcoord.integer] + ycoord.integer] + zcoord.integer];
41-
aba = _p[_p[_p[xcoord.integer] + ycoord.integer + 1] + zcoord.integer];
42-
aab = _p[_p[_p[xcoord.integer] + ycoord.integer] + zcoord.integer + 1];
43-
abb = _p[_p[_p[xcoord.integer] + ycoord.integer + 1] + zcoord.integer + 1];
44-
baa = _p[_p[_p[xcoord.integer + 1] + ycoord.integer] + zcoord.integer];
45-
bba = _p[_p[_p[xcoord.integer + 1] + ycoord.integer + 1] + zcoord.integer];
46-
bab = _p[_p[_p[xcoord.integer + 1] + ycoord.integer] + zcoord.integer + 1];
47-
bbb = _p[_p[_p[xcoord.integer + 1] + ycoord.integer + 1] + zcoord.integer + 1];
48-
49-
double x1, x2, y1, y2;
50-
x1 = Lerp(
39+
int a = _p[xcoord.integer];
40+
int b = _p[xcoord.integer + 1];
41+
int aa = _p[a + ycoord.integer];
42+
int ab = _p[a + ycoord.integer + 1];
43+
int ba = _p[b + ycoord.integer];
44+
int bb = _p[b + ycoord.integer + 1];
45+
46+
int aaa = _p[aa + zcoord.integer];
47+
int aba = _p[ab + zcoord.integer];
48+
int aab = _p[aa + zcoord.integer + 1];
49+
int abb = _p[ab + zcoord.integer + 1];
50+
int baa = _p[ba + zcoord.integer];
51+
int bba = _p[bb + zcoord.integer];
52+
int bab = _p[ba + zcoord.integer + 1];
53+
int bbb = _p[bb + zcoord.integer + 1];
54+
55+
var xa = new Vector4(
5156
Grad(aaa, xcoord.remainder, ycoord.remainder, zcoord.remainder),
52-
Grad(baa, xcoord.remainder - 1, ycoord.remainder, zcoord.remainder),
53-
u);
54-
x2 = Lerp(
5557
Grad(aba, xcoord.remainder, ycoord.remainder - 1, zcoord.remainder),
56-
Grad(bba, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder),
57-
u);
58-
y1 = Lerp(x1, x2, v);
59-
60-
x1 = Lerp(
6158
Grad(aab, xcoord.remainder, ycoord.remainder, zcoord.remainder - 1),
59+
Grad(abb, xcoord.remainder, ycoord.remainder - 1, zcoord.remainder - 1));
60+
var xb = new Vector4(
61+
Grad(baa, xcoord.remainder - 1, ycoord.remainder, zcoord.remainder),
62+
Grad(bba, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder),
6263
Grad(bab, xcoord.remainder - 1, ycoord.remainder, zcoord.remainder - 1),
63-
u);
64-
x2 = Lerp(
65-
Grad(abb, xcoord.remainder, ycoord.remainder - 1, zcoord.remainder - 1),
66-
Grad(bbb, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder - 1),
67-
u);
68-
y2 = Lerp(x1, x2, v);
69-
70-
return (Lerp(y1, y2, w) + 1) / 2;
64+
Grad(bbb, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder - 1));
65+
var xl = Vector4.Lerp(xa, xb, u);
66+
var ya = new Vector2(xl.X, xl.Z);
67+
var yb = new Vector2(xl.Y, xl.W);
68+
var yl = Vector2.Lerp(ya, yb, v);
69+
70+
return (Lerp(yl.X, yl.Y, w) + 1) / 2;
71+
}
72+
73+
public void Noise(float[,,] noise, Vector3 offset, Vector3 scale)
74+
{
75+
var xExtent = noise.GetUpperBound(0) + 1;
76+
var yExtent = noise.GetUpperBound(1) + 1;
77+
var zExtent = noise.GetUpperBound(2) + 1;
78+
79+
for (int x = 0; x < xExtent; x++)
80+
{
81+
var xOffset = offset.X + x * scale.X;
82+
var xcoord = Split(xOffset);
83+
var u = Fade(xcoord.remainder);
84+
85+
int a = _p[xcoord.integer];
86+
int b = _p[xcoord.integer + 1];
87+
for (int y = 0; y < yExtent; y++)
88+
{
89+
var yOffset = offset.Y + y * scale.Y;
90+
var ycoord = Split(yOffset);
91+
var v = Fade(ycoord.remainder);
92+
93+
int aa = _p[a + ycoord.integer];
94+
int ab = _p[a + ycoord.integer + 1];
95+
int ba = _p[b + ycoord.integer];
96+
int bb = _p[b + ycoord.integer + 1];
97+
for (int z = 0; z < zExtent; z++)
98+
{
99+
var zOffset = offset.Z + z * scale.Z;
100+
var zcoord = Split(zOffset);
101+
var w = Fade(zcoord.remainder);
102+
103+
int aaa = _p[aa + zcoord.integer];
104+
int aba = _p[ab + zcoord.integer];
105+
int aab = _p[aa + zcoord.integer + 1];
106+
int abb = _p[ab + zcoord.integer + 1];
107+
int baa = _p[ba + zcoord.integer];
108+
int bba = _p[bb + zcoord.integer];
109+
int bab = _p[ba + zcoord.integer + 1];
110+
int bbb = _p[bb + zcoord.integer + 1];
111+
112+
var xa = new Vector4(
113+
Grad(aaa, xcoord.remainder, ycoord.remainder, zcoord.remainder),
114+
Grad(aba, xcoord.remainder, ycoord.remainder - 1, zcoord.remainder),
115+
Grad(aab, xcoord.remainder, ycoord.remainder, zcoord.remainder - 1),
116+
Grad(abb, xcoord.remainder, ycoord.remainder - 1, zcoord.remainder - 1));
117+
var xb = new Vector4(
118+
Grad(baa, xcoord.remainder - 1, ycoord.remainder, zcoord.remainder),
119+
Grad(bba, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder),
120+
Grad(bab, xcoord.remainder - 1, ycoord.remainder, zcoord.remainder - 1),
121+
Grad(bbb, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder - 1));
122+
var xl = Vector4.Lerp(xa, xb, u);
123+
var ya = new Vector2(xl.X, xl.Z);
124+
var yb = new Vector2(xl.Y, xl.W);
125+
var yl = Vector2.Lerp(ya, yb, v);
126+
127+
noise[x, y, z] = (Lerp(yl.X, yl.Y, w) + 1) / 2;
128+
}
129+
}
130+
}
131+
}
132+
133+
public void AddNoise(float[,,] noise, Vector3 offset, Vector3 scale, float noiseScale)
134+
{
135+
var xExtent = noise.GetUpperBound(0) + 1;
136+
var yExtent = noise.GetUpperBound(1) + 1;
137+
var zExtent = noise.GetUpperBound(2) + 1;
138+
139+
for (int x = 0; x < xExtent; x++)
140+
{
141+
var xOffset = offset.X + x * scale.X;
142+
var xcoord = Split(xOffset);
143+
var u = Fade(xcoord.remainder);
144+
145+
int a = _p[xcoord.integer];
146+
int b = _p[xcoord.integer + 1];
147+
for (int y = 0; y < yExtent; y++)
148+
{
149+
var yOffset = offset.Y + y * scale.Y;
150+
var ycoord = Split(yOffset);
151+
var v = Fade(ycoord.remainder);
152+
153+
int aa = _p[a + ycoord.integer];
154+
int ab = _p[a + ycoord.integer + 1];
155+
int ba = _p[b + ycoord.integer];
156+
int bb = _p[b + ycoord.integer + 1];
157+
for (int z = 0; z < zExtent; z++)
158+
{
159+
var zOffset = offset.Z + z * scale.Z;
160+
var zcoord = Split(zOffset);
161+
var w = Fade(zcoord.remainder);
162+
163+
int aaa = _p[aa + zcoord.integer];
164+
int aba = _p[ab + zcoord.integer];
165+
int aab = _p[aa + zcoord.integer + 1];
166+
int abb = _p[ab + zcoord.integer + 1];
167+
int baa = _p[ba + zcoord.integer];
168+
int bba = _p[bb + zcoord.integer];
169+
int bab = _p[ba + zcoord.integer + 1];
170+
int bbb = _p[bb + zcoord.integer + 1];
171+
172+
var xa = new Vector4(
173+
Grad(aaa, xcoord.remainder, ycoord.remainder, zcoord.remainder),
174+
Grad(aba, xcoord.remainder, ycoord.remainder - 1, zcoord.remainder),
175+
Grad(aab, xcoord.remainder, ycoord.remainder, zcoord.remainder - 1),
176+
Grad(abb, xcoord.remainder, ycoord.remainder - 1, zcoord.remainder - 1));
177+
var xb = new Vector4(
178+
Grad(baa, xcoord.remainder - 1, ycoord.remainder, zcoord.remainder),
179+
Grad(bba, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder),
180+
Grad(bab, xcoord.remainder - 1, ycoord.remainder, zcoord.remainder - 1),
181+
Grad(bbb, xcoord.remainder - 1, ycoord.remainder - 1, zcoord.remainder - 1));
182+
var xl = Vector4.Lerp(xa, xb, u);
183+
var ya = new Vector2(xl.X, xl.Z);
184+
var yb = new Vector2(xl.Y, xl.W);
185+
var yl = Vector2.Lerp(ya, yb, v);
186+
187+
noise[x, y, z] += (Lerp(yl.X, yl.Y, w) + 1) / 2 * noiseScale;
188+
}
189+
}
190+
}
71191
}
72192

73-
private static (int integer, double remainder) Split(double value)
193+
private static (int integer, float remainder) Split(float value)
74194
{
75195
var integer = (int)value;
76196
return (integer % 256, value - integer);
77197
}
78198

79-
private static double Fade(double t)
199+
private static float Fade(float t)
80200
{
81201
// 6t^5 - 15t^4 + 10t^3
82202
return t * t * t * (t * (t * 6 - 15) + 10);
83203
}
84204

85205
// Source: http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html
86-
public static double Grad(int hash, double x, double y, double z)
206+
public static float Grad(int hash, float x, float y, float z)
87207
{
88208
switch (hash & 0xF)
89209
{
@@ -107,7 +227,7 @@ public static double Grad(int hash, double x, double y, double z)
107227
}
108228
}
109229

110-
public static double Lerp(double a, double b, double x) =>
230+
public static float Lerp(float a, float b, float x) =>
111231
a + x * (b - a);
112232
}
113233
}

0 commit comments

Comments
 (0)