PocketMine-MP 5.18.2 git-00e39821f06a4b6d728d35053c2621dbb19369ff
Simplex.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
25
27use const M_SQRT3;
28
36class Simplex extends Noise{
37 protected const grad3 = [
38 [1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0],
39 [1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1],
40 [0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1]
41 ];
42
43 protected const F2 = 0.5 * (M_SQRT3 - 1);
44 protected const G2 = (3 - M_SQRT3) / 6;
45 protected const G22 = self::G2 * 2.0 - 1;
46 protected const F3 = 1.0 / 3.0;
47 protected const G3 = 1.0 / 6.0;
48
49 protected float $offsetX;
50 protected float $offsetZ;
51 protected float $offsetY;
53 protected array $perm = [];
54
55 public function __construct(Random $random, int $octaves, float $persistence, float $expansion){
56 parent::__construct($octaves, $persistence, $expansion);
57
58 $this->offsetX = $random->nextFloat() * 256;
59 $this->offsetY = $random->nextFloat() * 256;
60 $this->offsetZ = $random->nextFloat() * 256;
61
62 for($i = 0; $i < 512; ++$i){
63 $this->perm[$i] = 0;
64 }
65
66 for($i = 0; $i < 256; ++$i){
67 $this->perm[$i] = $random->nextBoundedInt(256);
68 }
69
70 for($i = 0; $i < 256; ++$i){
71 $pos = $random->nextBoundedInt(256 - $i) + $i;
72 $old = $this->perm[$i];
73
74 $this->perm[$i] = $this->perm[$pos];
75 $this->perm[$pos] = $old;
76 $this->perm[$i + 256] = $this->perm[$i];
77 }
78
79 //this dummy call is necessary to produce the same RNG state as before latest refactors to this file
80 //previously this value would be used for offsetW
81 //TODO: this really needs to reset the RNG seed to avoid future RNG contamination
82 $random->nextSignedInt();
83 }
84
85 public function getNoise3D($x, $y, $z){
86 $x += $this->offsetX;
87 $y += $this->offsetY;
88 $z += $this->offsetZ;
89
90 // Skew the input space to determine which simplex cell we're in
91 $s = ($x + $y + $z) * self::F3; // Very nice and simple skew factor for 3D
92 $i = (int) ($x + $s);
93 $j = (int) ($y + $s);
94 $k = (int) ($z + $s);
95 $t = ($i + $j + $k) * self::G3;
96 // Unskew the cell origin back to (x,y,z) space
97 $x0 = $x - ($i - $t); // The x,y,z distances from the cell origin
98 $y0 = $y - ($j - $t);
99 $z0 = $z - ($k - $t);
100
101 // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
102
103 // Determine which simplex we are in.
104 if($x0 >= $y0){
105 if($y0 >= $z0){
106 $i1 = 1;
107 $j1 = 0;
108 $k1 = 0;
109 $i2 = 1;
110 $j2 = 1;
111 $k2 = 0;
112 } // X Y Z order
113 elseif($x0 >= $z0){
114 $i1 = 1;
115 $j1 = 0;
116 $k1 = 0;
117 $i2 = 1;
118 $j2 = 0;
119 $k2 = 1;
120 } // X Z Y order
121 else{
122 $i1 = 0;
123 $j1 = 0;
124 $k1 = 1;
125 $i2 = 1;
126 $j2 = 0;
127 $k2 = 1;
128 }
129 // Z X Y order
130 }else{ // x0<y0
131 if($y0 < $z0){
132 $i1 = 0;
133 $j1 = 0;
134 $k1 = 1;
135 $i2 = 0;
136 $j2 = 1;
137 $k2 = 1;
138 } // Z Y X order
139 elseif($x0 < $z0){
140 $i1 = 0;
141 $j1 = 1;
142 $k1 = 0;
143 $i2 = 0;
144 $j2 = 1;
145 $k2 = 1;
146 } // Y Z X order
147 else{
148 $i1 = 0;
149 $j1 = 1;
150 $k1 = 0;
151 $i2 = 1;
152 $j2 = 1;
153 $k2 = 0;
154 }
155 // Y X Z order
156 }
157
158 // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
159 // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
160 // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
161 // c = 1/6.
162 $x1 = $x0 - $i1 + self::G3; // Offsets for second corner in (x,y,z) coords
163 $y1 = $y0 - $j1 + self::G3;
164 $z1 = $z0 - $k1 + self::G3;
165 $x2 = $x0 - $i2 + 2.0 * self::G3; // Offsets for third corner in (x,y,z) coords
166 $y2 = $y0 - $j2 + 2.0 * self::G3;
167 $z2 = $z0 - $k2 + 2.0 * self::G3;
168 $x3 = $x0 - 1.0 + 3.0 * self::G3; // Offsets for last corner in (x,y,z) coords
169 $y3 = $y0 - 1.0 + 3.0 * self::G3;
170 $z3 = $z0 - 1.0 + 3.0 * self::G3;
171
172 // Work out the hashed gradient indices of the four simplex corners
173 $ii = $i & 255;
174 $jj = $j & 255;
175 $kk = $k & 255;
176
177 $n = 0;
178
179 // Calculate the contribution from the four corners
180 $t0 = 0.6 - $x0 * $x0 - $y0 * $y0 - $z0 * $z0;
181 if($t0 > 0){
182 $gi0 = self::grad3[$this->perm[$ii + $this->perm[$jj + $this->perm[$kk]]] % 12];
183 $n += $t0 * $t0 * $t0 * $t0 * ($gi0[0] * $x0 + $gi0[1] * $y0 + $gi0[2] * $z0);
184 }
185
186 $t1 = 0.6 - $x1 * $x1 - $y1 * $y1 - $z1 * $z1;
187 if($t1 > 0){
188 $gi1 = self::grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1 + $this->perm[$kk + $k1]]] % 12];
189 $n += $t1 * $t1 * $t1 * $t1 * ($gi1[0] * $x1 + $gi1[1] * $y1 + $gi1[2] * $z1);
190 }
191
192 $t2 = 0.6 - $x2 * $x2 - $y2 * $y2 - $z2 * $z2;
193 if($t2 > 0){
194 $gi2 = self::grad3[$this->perm[$ii + $i2 + $this->perm[$jj + $j2 + $this->perm[$kk + $k2]]] % 12];
195 $n += $t2 * $t2 * $t2 * $t2 * ($gi2[0] * $x2 + $gi2[1] * $y2 + $gi2[2] * $z2);
196 }
197
198 $t3 = 0.6 - $x3 * $x3 - $y3 * $y3 - $z3 * $z3;
199 if($t3 > 0){
200 $gi3 = self::grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1 + $this->perm[$kk + 1]]] % 12];
201 $n += $t3 * $t3 * $t3 * $t3 * ($gi3[0] * $x3 + $gi3[1] * $y3 + $gi3[2] * $z3);
202 }
203
204 // Add contributions from each corner to get the noise value.
205 // The result is scaled to stay just inside [-1,1]
206 return 32.0 * $n;
207 }
208
215 public function getNoise2D($x, $y){
216 $x += $this->offsetX;
217 $y += $this->offsetY;
218
219 // Skew the input space to determine which simplex cell we're in
220 $s = ($x + $y) * self::F2; // Hairy factor for 2D
221 $i = (int) ($x + $s);
222 $j = (int) ($y + $s);
223 $t = ($i + $j) * self::G2;
224 // Unskew the cell origin back to (x,y) space
225 $x0 = $x - ($i - $t); // The x,y distances from the cell origin
226 $y0 = $y - ($j - $t);
227
228 // For the 2D case, the simplex shape is an equilateral triangle.
229
230 // Determine which simplex we are in.
231 if($x0 > $y0){
232 $i1 = 1;
233 $j1 = 0;
234 } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
235 else{
236 $i1 = 0;
237 $j1 = 1;
238 }
239 // upper triangle, YX order: (0,0)->(0,1)->(1,1)
240
241 // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
242 // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
243 // c = (3-sqrt(3))/6
244
245 $x1 = $x0 - $i1 + self::G2; // Offsets for middle corner in (x,y) unskewed coords
246 $y1 = $y0 - $j1 + self::G2;
247 $x2 = $x0 + self::G22; // Offsets for last corner in (x,y) unskewed coords
248 $y2 = $y0 + self::G22;
249
250 // Work out the hashed gradient indices of the three simplex corners
251 $ii = $i & 255;
252 $jj = $j & 255;
253
254 $n = 0;
255
256 // Calculate the contribution from the three corners
257 $t0 = 0.5 - $x0 * $x0 - $y0 * $y0;
258 if($t0 > 0){
259 $gi0 = self::grad3[$this->perm[$ii + $this->perm[$jj]] % 12];
260 $n += $t0 * $t0 * $t0 * $t0 * ($gi0[0] * $x0 + $gi0[1] * $y0); // (x,y) of grad3 used for 2D gradient
261 }
262
263 $t1 = 0.5 - $x1 * $x1 - $y1 * $y1;
264 if($t1 > 0){
265 $gi1 = self::grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1]] % 12];
266 $n += $t1 * $t1 * $t1 * $t1 * ($gi1[0] * $x1 + $gi1[1] * $y1);
267 }
268
269 $t2 = 0.5 - $x2 * $x2 - $y2 * $y2;
270 if($t2 > 0){
271 $gi2 = self::grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1]] % 12];
272 $n += $t2 * $t2 * $t2 * $t2 * ($gi2[0] * $x2 + $gi2[1] * $y2);
273 }
274
275 // Add contributions from each corner to get the noise value.
276 // The result is scaled to return values in the interval [-1,1].
277 return 70.0 * $n;
278 }
279}