= 0 ? (int) $x : (int) ($x - 1); } public static function fade($x){ return $x * $x * $x * ($x * ($x * 6 - 15) + 10); } public static function lerp($x, $y, $z){ return $y + $x * ($z - $y); } public static function linearLerp($x, $x1, $x2, $q0, $q1){ return (($x2 - $x) / ($x2 - $x1)) * $q0 + (($x - $x1) / ($x2 - $x1)) * $q1; } public static function bilinearLerp($x, $y, $q00, $q01, $q10, $q11, $x1, $x2, $y1, $y2){ $dx1 = (($x2 - $x) / ($x2 - $x1)); $dx2 = (($x - $x1) / ($x2 - $x1)); return (($y2 - $y) / ($y2 - $y1)) * ( $dx1 * $q00 + $dx2 * $q10 ) + (($y - $y1) / ($y2 - $y1)) * ( $dx1 * $q01 + $dx2 * $q11 ); } public static function trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2){ $dx1 = (($x2 - $x) / ($x2 - $x1)); $dx2 = (($x - $x1) / ($x2 - $x1)); $dy1 = (($y2 - $y) / ($y2 - $y1)); $dy2 = (($y - $y1) / ($y2 - $y1)); return (($z2 - $z) / ($z2 - $z1)) * ( $dy1 * ( $dx1 * $q000 + $dx2 * $q100 ) + $dy2 * ( $dx1 * $q001 + $dx2 * $q101 ) ) + (($z - $z1) / ($z2 - $z1)) * ( $dy1 * ( $dx1 * $q010 + $dx2 * $q110 ) + $dy2 * ( $dx1 * $q011 + $dx2 * $q111 ) ); } public static function grad($hash, $x, $y, $z){ $hash &= 15; $u = $hash < 8 ? $x : $y; $v = $hash < 4 ? $y : (($hash === 12 or $hash === 14) ? $x : $z); return (($hash & 1) === 0 ? $u : -$u) + (($hash & 2) === 0 ? $v : -$v); } abstract public function getNoise2D($x, $z); abstract public function getNoise3D($x, $y, $z); public function noise2D($x, $z, $normalized = false){ $result = 0; $amp = 1; $freq = 1; $max = 0; $x *= $this->expansion; $z *= $this->expansion; for($i = 0; $i < $this->octaves; ++$i){ $result += $this->getNoise2D($x * $freq, $z * $freq) * $amp; $max += $amp; $freq *= 2; $amp *= $this->persistence; } if($normalized === true){ $result /= $max; } return $result; } public function noise3D($x, $y, $z, $normalized = false){ $result = 0; $amp = 1; $freq = 1; $max = 0; $x *= $this->expansion; $y *= $this->expansion; $z *= $this->expansion; for($i = 0; $i < $this->octaves; ++$i){ $result += $this->getNoise3D($x * $freq, $y * $freq, $z * $freq) * $amp; $max += $amp; $freq *= 2; $amp *= $this->persistence; } if($normalized === true){ $result /= $max; } return $result; } /** * @param int $xSize * @param int $samplingRate * @param int $x * @param int $y * @param int $z * * @return \SplFixedArray */ public function getFastNoise1D(int $xSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{ if($samplingRate === 0){ throw new \InvalidArgumentException("samplingRate cannot be 0"); } if($xSize % $samplingRate !== 0){ throw new \InvalidArgumentException("xSize % samplingRate must return 0"); } $noiseArray = new \SplFixedArray($xSize + 1); for($xx = 0; $xx <= $xSize; $xx += $samplingRate){ $noiseArray[$xx] = $this->noise3D($xx + $x, $y, $z); } for($xx = 0; $xx < $xSize; ++$xx){ if($xx % $samplingRate !== 0){ $nx = (int) ($xx / $samplingRate) * $samplingRate; $noiseArray[$xx] = self::linearLerp($xx, $nx, $nx + $samplingRate, $noiseArray[$nx], $noiseArray[$nx + $samplingRate]); } } return $noiseArray; } /** * @param int $xSize * @param int $zSize * @param int $samplingRate * @param int $x * @param int $y * @param int $z * * @return \SplFixedArray */ public function getFastNoise2D(int $xSize, int $zSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{ assert($samplingRate !== 0, new \InvalidArgumentException("samplingRate cannot be 0")); assert($xSize % $samplingRate === 0, new \InvalidArgumentException("xSize % samplingRate must return 0")); assert($zSize % $samplingRate === 0, new \InvalidArgumentException("zSize % samplingRate must return 0")); $noiseArray = new \SplFixedArray($xSize + 1); for($xx = 0; $xx <= $xSize; $xx += $samplingRate){ $noiseArray[$xx] = new \SplFixedArray($zSize + 1); for($zz = 0; $zz <= $zSize; $zz += $samplingRate){ $noiseArray[$xx][$zz] = $this->noise3D($x + $xx, $y, $z + $zz); } } for($xx = 0; $xx < $xSize; ++$xx){ if($xx % $samplingRate !== 0){ $noiseArray[$xx] = new \SplFixedArray($zSize + 1); } for($zz = 0; $zz < $zSize; ++$zz){ if($xx % $samplingRate !== 0 or $zz % $samplingRate !== 0){ $nx = (int) ($xx / $samplingRate) * $samplingRate; $nz = (int) ($zz / $samplingRate) * $samplingRate; $noiseArray[$xx][$zz] = Noise::bilinearLerp( $xx, $zz, $noiseArray[$nx][$nz], $noiseArray[$nx][$nz + $samplingRate], $noiseArray[$nx + $samplingRate][$nz], $noiseArray[$nx + $samplingRate][$nz + $samplingRate], $nx, $nx + $samplingRate, $nz, $nz + $samplingRate ); } } } return $noiseArray; } /** * @param int $xSize * @param int $ySize * @param int $zSize * @param int $xSamplingRate * @param int $ySamplingRate * @param int $zSamplingRate * @param int $x * @param int $y * @param int $z * * @return array */ public function getFastNoise3D(int $xSize, int $ySize, int $zSize, int $xSamplingRate, int $ySamplingRate, int $zSamplingRate, int $x, int $y, int $z) : array{ assert($xSamplingRate !== 0, new \InvalidArgumentException("xSamplingRate cannot be 0")); assert($zSamplingRate !== 0, new \InvalidArgumentException("zSamplingRate cannot be 0")); assert($ySamplingRate !== 0, new \InvalidArgumentException("ySamplingRate cannot be 0")); assert($xSize % $xSamplingRate === 0, new \InvalidArgumentException("xSize % xSamplingRate must return 0")); assert($zSize % $zSamplingRate === 0, new \InvalidArgumentException("zSize % zSamplingRate must return 0")); assert($ySize % $ySamplingRate === 0, new \InvalidArgumentException("ySize % ySamplingRate must return 0")); $noiseArray = array_fill(0, $xSize + 1, array_fill(0, $zSize + 1, [])); for($xx = 0; $xx <= $xSize; $xx += $xSamplingRate){ for($zz = 0; $zz <= $zSize; $zz += $zSamplingRate){ for($yy = 0; $yy <= $ySize; $yy += $ySamplingRate){ $noiseArray[$xx][$zz][$yy] = $this->noise3D($x + $xx, $y + $yy, $z + $zz, true); } } } for($xx = 0; $xx < $xSize; ++$xx){ for($zz = 0; $zz < $zSize; ++$zz){ for($yy = 0; $yy < $ySize; ++$yy){ if($xx % $xSamplingRate !== 0 or $zz % $zSamplingRate !== 0 or $yy % $ySamplingRate !== 0){ $nx = (int) ($xx / $xSamplingRate) * $xSamplingRate; $ny = (int) ($yy / $ySamplingRate) * $ySamplingRate; $nz = (int) ($zz / $zSamplingRate) * $zSamplingRate; $nnx = $nx + $xSamplingRate; $nny = $ny + $ySamplingRate; $nnz = $nz + $zSamplingRate; $dx1 = (($nnx - $xx) / ($nnx - $nx)); $dx2 = (($xx - $nx) / ($nnx - $nx)); $dy1 = (($nny - $yy) / ($nny - $ny)); $dy2 = (($yy - $ny) / ($nny - $ny)); $noiseArray[$xx][$zz][$yy] = (($nnz - $zz) / ($nnz - $nz)) * ( $dy1 * ( $dx1 * $noiseArray[$nx][$nz][$ny] + $dx2 * $noiseArray[$nnx][$nz][$ny] ) + $dy2 * ( $dx1 * $noiseArray[$nx][$nz][$nny] + $dx2 * $noiseArray[$nnx][$nz][$nny] ) ) + (($zz - $nz) / ($nnz - $nz)) * ( $dy1 * ( $dx1 * $noiseArray[$nx][$nnz][$ny] + $dx2 * $noiseArray[$nnx][$nnz][$ny] ) + $dy2 * ( $dx1 * $noiseArray[$nx][$nnz][$nny] + $dx2 * $noiseArray[$nnx][$nnz][$nny] ) ); } } } } return $noiseArray; } public function setOffset($x, $y, $z){ $this->offsetX = $x; $this->offsetY = $y; $this->offsetZ = $z; } }