PocketMine-MP 5.37.2 git-e507eb5e50da3ead3ae88ed2324df21e75820019
Loading...
Searching...
No Matches
Noise.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
28
29use function array_fill;
30use function assert;
31
32abstract class Noise{
33
43 public static function linearLerp($x, $x1, $x2, $q0, $q1){
44 return (($x2 - $x) / ($x2 - $x1)) * $q0 + (($x - $x1) / ($x2 - $x1)) * $q1;
45 }
46
61 public static function bilinearLerp($x, $y, $q00, $q01, $q10, $q11, $x1, $x2, $y1, $y2){
62 $dx1 = (($x2 - $x) / ($x2 - $x1));
63 $dx2 = (($x - $x1) / ($x2 - $x1));
64
65 return (($y2 - $y) / ($y2 - $y1)) * (
66 $dx1 * $q00 + $dx2 * $q10
67 ) + (($y - $y1) / ($y2 - $y1)) * (
68 $dx1 * $q01 + $dx2 * $q11
69 );
70 }
71
93 public static function trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2){
94 $dx1 = (($x2 - $x) / ($x2 - $x1));
95 $dx2 = (($x - $x1) / ($x2 - $x1));
96 $dy1 = (($y2 - $y) / ($y2 - $y1));
97 $dy2 = (($y - $y1) / ($y2 - $y1));
98
99 return (($z2 - $z) / ($z2 - $z1)) * (
100 $dy1 * (
101 $dx1 * $q000 + $dx2 * $q100
102 ) + $dy2 * (
103 $dx1 * $q001 + $dx2 * $q101
104 )
105 ) + (($z - $z1) / ($z2 - $z1)) * (
106 $dy1 * (
107 $dx1 * $q010 + $dx2 * $q110
108 ) + $dy2 * (
109 $dx1 * $q011 + $dx2 * $q111
110 )
111 );
112 }
113
114 public function __construct(
115 protected int $octaves,
116 protected float $persistence,
117 protected float $expansion
118 ){}
119
126 abstract public function getNoise2D($x, $z);
127
135 abstract public function getNoise3D($x, $y, $z);
136
144 public function noise2D($x, $z, $normalized = false){
145 $result = 0;
146 $amp = 1;
147 $freq = 1;
148 $max = 0;
149
150 $x *= $this->expansion;
151 $z *= $this->expansion;
152
153 for($i = 0; $i < $this->octaves; ++$i){
154 $result += $this->getNoise2D($x * $freq, $z * $freq) * $amp;
155 $max += $amp;
156 $freq *= 2;
157 $amp *= $this->persistence;
158 }
159
160 if($normalized === true){
161 $result /= $max;
162 }
163
164 return $result;
165 }
166
175 public function noise3D($x, $y, $z, $normalized = false){
176 $result = 0;
177 $amp = 1;
178 $freq = 1;
179 $max = 0;
180
181 $x *= $this->expansion;
182 $y *= $this->expansion;
183 $z *= $this->expansion;
184
185 for($i = 0; $i < $this->octaves; ++$i){
186 $result += $this->getNoise3D($x * $freq, $y * $freq, $z * $freq) * $amp;
187 $max += $amp;
188 $freq *= 2;
189 $amp *= $this->persistence;
190 }
191
192 if($normalized === true){
193 $result /= $max;
194 }
195
196 return $result;
197 }
198
203 public function getFastNoise1D(int $xSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
204 if($samplingRate === 0){
205 throw new \InvalidArgumentException("samplingRate cannot be 0");
206 }
207 if($xSize % $samplingRate !== 0){
208 throw new \InvalidArgumentException("xSize % samplingRate must return 0");
209 }
210
212 $noiseArray = new \SplFixedArray($xSize + 1);
213
214 for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
215 $noiseArray[$xx] = $this->noise3D($xx + $x, $y, $z);
216 }
217
218 for($xx = 0; $xx < $xSize; ++$xx){
219 if($xx % $samplingRate !== 0){
220 $nx = (int) ($xx / $samplingRate) * $samplingRate;
221 $noiseArray[$xx] = self::linearLerp(
222 x: $xx,
223 x1: $nx,
224 x2: $nx + $samplingRate,
225 q0: $noiseArray[$nx],
226 q1: $noiseArray[$nx + $samplingRate]
227 );
228 }
229 }
230
231 return $noiseArray;
232 }
233
238 public function getFastNoise2D(int $xSize, int $zSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
239 assert($samplingRate !== 0, new \InvalidArgumentException("samplingRate cannot be 0"));
240
241 assert($xSize % $samplingRate === 0, new \InvalidArgumentException("xSize % samplingRate must return 0"));
242 assert($zSize % $samplingRate === 0, new \InvalidArgumentException("zSize % samplingRate must return 0"));
243
245 $noiseArray = new \SplFixedArray($xSize + 1);
246
247 for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
248 $noiseArray[$xx] = new \SplFixedArray($zSize + 1);
249 for($zz = 0; $zz <= $zSize; $zz += $samplingRate){
250 $noiseArray[$xx][$zz] = $this->noise3D($x + $xx, $y, $z + $zz);
251 }
252 }
253
254 for($xx = 0; $xx < $xSize; ++$xx){
255 if($xx % $samplingRate !== 0){
256 $noiseArray[$xx] = new \SplFixedArray($zSize + 1);
257 }
258
259 for($zz = 0; $zz < $zSize; ++$zz){
260 if($xx % $samplingRate !== 0 || $zz % $samplingRate !== 0){
261 $nx = (int) ($xx / $samplingRate) * $samplingRate;
262 $nz = (int) ($zz / $samplingRate) * $samplingRate;
263 $noiseArray[$xx][$zz] = Noise::bilinearLerp(
264 x: $xx,
265 y: $zz,
266 q00: $noiseArray[$nx][$nz],
267 q01: $noiseArray[$nx][$nz + $samplingRate],
268 q10: $noiseArray[$nx + $samplingRate][$nz],
269 q11: $noiseArray[$nx + $samplingRate][$nz + $samplingRate],
270 x1: $nx,
271 x2: $nx + $samplingRate,
272 y1: $nz,
273 y2: $nz + $samplingRate
274 );
275 }
276 }
277 }
278
279 return $noiseArray;
280 }
281
285 public function getFastNoise3D(int $xSize, int $ySize, int $zSize, int $xSamplingRate, int $ySamplingRate, int $zSamplingRate, int $x, int $y, int $z) : array{
286
287 assert($xSamplingRate !== 0, new \InvalidArgumentException("xSamplingRate cannot be 0"));
288 assert($zSamplingRate !== 0, new \InvalidArgumentException("zSamplingRate cannot be 0"));
289 assert($ySamplingRate !== 0, new \InvalidArgumentException("ySamplingRate cannot be 0"));
290
291 assert($xSize % $xSamplingRate === 0, new \InvalidArgumentException("xSize % xSamplingRate must return 0"));
292 assert($zSize % $zSamplingRate === 0, new \InvalidArgumentException("zSize % zSamplingRate must return 0"));
293 assert($ySize % $ySamplingRate === 0, new \InvalidArgumentException("ySize % ySamplingRate must return 0"));
294
295 $noiseArray = array_fill(0, $xSize + 1, array_fill(0, $zSize + 1, array_fill(0, $ySize + 1, 0)));
296
297 for($xx = 0; $xx <= $xSize; $xx += $xSamplingRate){
298 for($zz = 0; $zz <= $zSize; $zz += $zSamplingRate){
299 for($yy = 0; $yy <= $ySize; $yy += $ySamplingRate){
300 $noiseArray[$xx][$zz][$yy] = $this->noise3D($x + $xx, $y + $yy, $z + $zz, true);
301 }
302 }
303 }
304
314 $xLerpStep = 1 / $xSamplingRate;
315 $yLerpStep = 1 / $ySamplingRate;
316 $zLerpStep = 1 / $zSamplingRate;
317
318 for($leftX = 0; $leftX < $xSize; $leftX += $xSamplingRate){
319 $rightX = $leftX + $xSamplingRate;
320
321 for($leftZ = 0; $leftZ < $zSize; $leftZ += $zSamplingRate){
322 $rightZ = $leftZ + $zSamplingRate;
323
324 for($leftY = 0; $leftY < $ySize; $leftY += $ySamplingRate){
325 $rightY = $leftY + $ySamplingRate;
326
327 //Fetch the corner samples first - this avoids multidimensional array lookups in the inner loops,
328 //which are slow
329 $c000 = $noiseArray[$leftX][$leftZ][$leftY];
330 $c100 = $noiseArray[$rightX][$leftZ][$leftY];
331 $c001 = $noiseArray[$leftX][$leftZ][$rightY];
332 $c101 = $noiseArray[$rightX][$leftZ][$rightY];
333 $c010 = $noiseArray[$leftX][$rightZ][$leftY];
334 $c110 = $noiseArray[$rightX][$rightZ][$leftY];
335 $c011 = $noiseArray[$leftX][$rightZ][$rightY];
336 $c111 = $noiseArray[$rightX][$rightZ][$rightY];
337
338 //Now, lerp all the cells enclosed by the corner samples
339 for($xStep = 0; $xStep < $xSamplingRate; $xStep++){
340 $xx = $leftX + $xStep;
341 $dx2 = $xStep * $xLerpStep;
342 $dx1 = 1 - $dx2;
343
344 //Lerp along the x axis first
345 $x00 = ($c000 * $dx1) + ($c100 * $dx2);
346 $x01 = ($c001 * $dx1) + ($c101 * $dx2);
347 $x10 = ($c010 * $dx1) + ($c110 * $dx2);
348 $x11 = ($c011 * $dx1) + ($c111 * $dx2);
349
350 for($zStep = 0; $zStep < $zSamplingRate; $zStep++){
351 $zz = $leftZ + $zStep;
352 $dz2 = $zStep * $zLerpStep;
353 $dz1 = 1 - $dz2;
354
355 //Then, lerp the x lerped axis values along the z axis
356 $z0 = $x00 * $dz1 + $x10 * $dz2;
357 $z1 = $x01 * $dz1 + $x11 * $dz2;
358
359 //Skip first row if these are both zero
360 $yStart = $xStep === 0 && $zStep === 0 ? 1 : 0;
361 for($yStep = $yStart; $yStep < $ySamplingRate; $yStep++){
362 $yy = $leftY + $yStep;
363 $dy2 = $yStep * $yLerpStep;
364 $dy1 = 1 - $dy2;
365
366 //Finally, lerp the x/z lerped values along the y axis
367 $noiseArray[$xx][$zz][$yy] = $dy1 * $z0 + $dy2 * $z1;
368 }
369 }
370 }
371 }
372 }
373 }
374
375 return $noiseArray;
376 }
377}
noise3D($x, $y, $z, $normalized=false)
Definition Noise.php:175
getFastNoise3D(int $xSize, int $ySize, int $zSize, int $xSamplingRate, int $ySamplingRate, int $zSamplingRate, int $x, int $y, int $z)
Definition Noise.php:285
static linearLerp($x, $x1, $x2, $q0, $q1)
Definition Noise.php:43
static trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2)
Definition Noise.php:93
static bilinearLerp($x, $y, $q00, $q01, $q10, $q11, $x1, $x2, $y1, $y2)
Definition Noise.php:61
getFastNoise1D(int $xSize, int $samplingRate, int $x, int $y, int $z)
Definition Noise.php:203
getFastNoise2D(int $xSize, int $zSize, int $samplingRate, int $x, int $y, int $z)
Definition Noise.php:238
noise2D($x, $z, $normalized=false)
Definition Noise.php:144