Created
April 17, 2020 13:54
-
-
Save BlackScorp/e720ad3dbc6c276aad6049be4ef55e1c to your computer and use it in GitHub Desktop.
perlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
set_time_limit(0); | |
error_reporting(-1); | |
ini_set('display_errors', 'On'); | |
require_once __DIR__ . '/Noise.php'; | |
/** | |
* Tatsächlich zu generierende Kartengröße | |
*/ | |
$mapWidth = 480; | |
$mapHeight = 360; | |
/** | |
* Region größe | |
*/ | |
$regionWidth = $mapWidth * 0.2; | |
$regionHeight = $mapHeight * 0.2; | |
/** | |
* Vergrößerung der Karte | |
*/ | |
$displaWidth = $mapWidth * 6; | |
$displayHeight = $mapHeight * 6; | |
$noise = new Noise(); | |
$noiseImage = imagecreatetruecolor($mapWidth, $mapHeight); | |
$boundImage = imagecreatetruecolor($mapWidth, $mapHeight); | |
imagecolorallocate($boundImage, 0, 0, 0); | |
$whiteColor = imagecolorallocate($boundImage, 255, 255, 255); | |
$blackColor =imagecolorallocate($boundImage, 0, 0, 0); | |
imagegradientellipse($boundImage, ~~($mapWidth/2), ~~($mapHeight/2), ~~($mapWidth), ~~($mapHeight), $whiteColor,$blackColor); | |
function imagegradientellipse($image, $cx, $cy, $w, $h, $ic, $oc){ | |
$w = abs($w); | |
$h = abs($h); | |
$oc = array(0xFF & ($oc >> 0x10), 0xFF & ($oc >> 0x8), 0xFF & $oc); | |
$ic = array(0xFF & ($ic >> 0x10), 0xFF & ($ic >> 0x8), 0xFF & $ic); | |
$c0 = ($oc[0] - $ic[0]) / $w; | |
$c1 = ($oc[1] - $ic[1]) / $w; | |
$c2 = ($oc[2] - $ic[2]) / $w; | |
$i = 0; | |
$j = 0; | |
$is = ($w<$h)?($w/$h):1; | |
$js = ($h<$w)?($h/$w):1; | |
while(1){ | |
$r = $oc[0] - floor($i * $c0); | |
$g = $oc[1] - floor($i * $c1); | |
$b = $oc[2] - floor($i * $c2); | |
$c = imagecolorallocate($image, $r, $g, $b); | |
imagefilledellipse($image, $cx, $cy, $w-$i, $h-$j, $c); | |
if($i < $w){ | |
$i += $is; | |
} | |
if($j < $h){ | |
$j += $js; | |
} | |
if($i >= $w && $j >= $h){ | |
break; | |
} | |
} | |
} | |
$noise->setBoundImage($boundImage); | |
$colorMap = array_fill(0, 30, imagecolorallocate($noiseImage, 0, 0, 50)); | |
$colorMap = array_merge($colorMap, array_fill(31, 20, imagecolorallocate($noiseImage, 0, 0, 100))); | |
$colorMap = array_merge($colorMap, array_fill(51, 30, imagecolorallocate($noiseImage, 0, 0, 150))); | |
$colorMap = array_merge($colorMap, array_fill(81, 10, imagecolorallocate($noiseImage, 222, 184, 135))); | |
$colorMap = array_merge($colorMap, array_fill(91, 20, imagecolorallocate($noiseImage, 0, 100, 0))); | |
$colorMap = array_merge($colorMap, array_fill(111, 20, imagecolorallocate($noiseImage, 0, 150, 0))); | |
$colorMap = array_merge($colorMap, array_fill(131, 20, imagecolorallocate($noiseImage, 135, 135, 135))); | |
$colorMap = array_merge($colorMap, array_fill(151, 20, imagecolorallocate($noiseImage, 135, 255, 255))); | |
$colorMap = array_merge($colorMap, array_fill(171, 84, imagecolorallocate($noiseImage, 255, 255, 255))); | |
for ($y = 0; $y < $mapHeight; $y += 1) { | |
for ($x = 0; $x < $mapWidth; $x += 1) { | |
$locationX = $x / $regionWidth; | |
$locationY = $y / $regionHeight; | |
$locationX *= $regionWidth / $regionHeight; | |
$num = $noise->fbm($locationX, $locationY,6,$x,$y); | |
$greyValue = ~~($noise->mix(0, 255, $num)); | |
$color = $colorMap[$greyValue]; | |
// $color = imagecolorallocate($noiseImage, $greyValue, $greyValue, $greyValue); | |
imagesetpixel($noiseImage, $x, $y, $color); | |
} | |
} | |
$image = imagecreatetruecolor($displaWidth, $displayHeight); | |
imagecopyresampled($image, $noiseImage, 0, 0, 0, 0, $displaWidth, $displayHeight, $mapWidth, $mapHeight); | |
header('Content-Type:image/png'); | |
imagepng($image); | |
imagedestroy($image); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Noise | |
{ | |
private $boundImage = null; | |
private $cachedValues = []; | |
private $amplitude = 0.5; | |
private $frequency = 2.0; | |
private $boundCache = []; | |
private $base = []; | |
private $seed; | |
public function __construct(int $seed = null) | |
{ | |
if (!$seed) { | |
$seed = date('His'); | |
} | |
$this->seed = $seed; | |
mt_srand($seed); | |
$this->base = [mt_rand(0, $this->seed), mt_rand(0, $this->seed)]; | |
} | |
private function random($x, $y) | |
{ | |
$cacheKey = $x . '_' . $y; | |
if (isset($this->cachedValues[$cacheKey])) { | |
return $this->cachedValues[$cacheKey]; | |
} | |
$dotProduct = $this->dot($x, $y, $this->base[0], $this->base[1]); | |
$value = $this->fract(sin($dotProduct) * $this->seed); | |
$this->cachedValues[$cacheKey] = $value; | |
return $value; | |
} | |
public function mix($x, $y, $alpha) | |
{ | |
return $x * (1 - $alpha) + $y * $alpha; | |
} | |
public function getNoise($x, $y) | |
{ | |
$x += $this->seed; | |
$y += $this->seed; | |
$xi = floor($x); | |
$yi = floor($y); | |
$xf = $this->fract($x); | |
$yf = $this->fract($y); | |
$a = $this->random($xi, $yi); | |
$b = $this->random($xi + 1, $yi); | |
$c = $this->random($xi, $yi + 1); | |
$d = $this->random($xi + 1, $yi + 1); | |
$ux = $xf * $xf * (3.0 - 2.0 * $xf); | |
$uy = $yf * $yf * (3.0 - 2.0 * $yf); | |
return $this->mix($a, $b, $ux) + ($c - $a) * $uy * (1.0 - $ux) + ($d - $b) * $ux * $uy; | |
} | |
public function fbm($x, $y, $octaves = 6, $originalX = 0, $originalY = 0) | |
{ | |
$value = 0.0; | |
$amplitude = $this->amplitude; | |
$frequency = $this->frequency; | |
for ($i = 0; $i < $octaves; $i++) { | |
if($this->boundImage){ | |
$value1 = $this->getNoise($x, $y); | |
$value2 = $this->getBoundImageNoise($originalX,$originalY); | |
$value += $amplitude * $this->mix($value1,$value2,0.6); | |
}else{ | |
$value += $amplitude * $this->getNoise($x, $y); | |
} | |
$x *= $frequency; | |
$y *= $frequency; | |
$amplitude *= $this->amplitude; | |
} | |
return $value; | |
} | |
private function dot($srcX, $srcY, $destX, $destY): float | |
{ | |
return array_sum(array_map(function ($a, $b) { | |
return $a * $b; | |
}, [$srcX, $srcY], [$destX, $destY])); | |
} | |
private function fract(float $value) | |
{ | |
return (float)($value - floor($value)); | |
} | |
public function setBoundImage($boundImage) | |
{ | |
$this->boundImage = $boundImage; | |
} | |
public function scale($value, $baseMin, $baseMax, $limitMin, $limitMax) | |
{ | |
return (($limitMax - $limitMin) * ($value - $baseMin) / ($baseMax - $baseMin)) + $limitMin; | |
} | |
private function colorToValue($color) | |
{ | |
$values = imagecolorsforindex($this->boundImage, $color); | |
return $values["red"]; | |
} | |
public function getBoundImageNoise($x, $y) | |
{ | |
$cacheKey = $x . '_' . $y; | |
if (isset($this->boundCache[$cacheKey])) { | |
return $this->boundCache[$cacheKey]; | |
} | |
$value = $this->scale($this->colorToValue(imagecolorat($this->boundImage, $x, $y)), 0, 255, 0.0, 1.0); | |
$this->boundCache[$cacheKey] = $value; | |
return $value; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Port of Ken Perlin's "Improved Noise" | |
* http://mrl.nyu.edu/~perlin/noise/ | |
*/ | |
class PerlinNoise | |
{ | |
var $p; | |
var $permutation; | |
/** @var int */ | |
var $seed; | |
function __construct($seed = null) | |
{ | |
//Initialize the permutation array | |
$this->p = array(); | |
$this->permutation = array(151,160,137,91,90,15, | |
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, | |
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, | |
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, | |
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, | |
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, | |
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, | |
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, | |
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, | |
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, | |
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, | |
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, | |
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 | |
); | |
//Populate it | |
for ($i=0; $i < 256 ; $i++) { | |
$this->p[256+$i] = $this->p[$i] = $this->permutation[$i]; | |
} | |
//And set the seed | |
if ($seed === null) { | |
$this->seed = microtime(true) * 10000; | |
} else { | |
$this->seed = $seed; | |
} | |
} | |
function noise($x, $y, $z, array $octaves) | |
{ | |
//Set the initial value and initial size | |
$value = 0.0; | |
$initialSize = $octaves[0]; | |
//Add finer and finer hues of smoothed noise together | |
foreach ($octaves as $octave) { | |
$value += $this->smoothNoise($x / $octave, $y / $octave, $z / $octave) * $octave; | |
} | |
//Return the result over the initial size | |
return $value / $initialSize; | |
} | |
//This function determines what cube the point passed resides in | |
//and determines its value. | |
function smoothNoise($x, $y, $z) | |
{ | |
//Offset each coordinate by the seed value | |
$x += $this->seed; | |
$y += $this->seed; | |
$z += $this->seed; | |
$origX = $x; | |
$origY = $y; | |
$origZ = $z; | |
$X1 = (int)floor($x) & 255; // FIND UNIT CUBE THAT | |
$Y1 = (int)floor($y) & 255; // CONTAINS POINT. | |
$Z1 = (int)floor($z) & 255; | |
$x -= floor($x); // FIND RELATIVE X,Y,Z | |
$y -= floor($y); // OF POINT IN CUBE. | |
$z -= floor($z); | |
$u = $this->fade($x); // COMPUTE FADE CURVES | |
$v = $this->fade($y); // FOR EACH OF X,Y,Z. | |
$w = $this->fade($z); | |
$A = $this->p[$X1]+$Y1; | |
$AA = $this->p[$A]+$Z1; | |
$AB = $this->p[$A+1]+$Z1; // HASH COORDINATES OF | |
$B = $this->p[$X1+1]+$Y1; | |
$BA = $this->p[$B]+$Z1; | |
$BB = $this->p[$B+1]+$Z1; // THE 8 CUBE CORNERS, | |
//Interpolate between the 8 points determined | |
// AND ADD BLENDED RESULTS FROM 8 CORNERS OF CUBE | |
$result = $this->lerp($w, $this->lerp($v, $this->lerp($u, $this->grad($this->p[$AA ], $x , $y , $z ), | |
$this->grad($this->p[$BA ], $x-1, $y , $z )), | |
$this->lerp($u, $this->grad($this->p[$AB ], $x , $y-1, $z ), | |
$this->grad($this->p[$BB ], $x-1, $y-1, $z ))), | |
$this->lerp($v, $this->lerp($u, $this->grad($this->p[$AA+1], $x , $y , $z-1 ), | |
$this->grad($this->p[$BA+1], $x-1, $y , $z-1 )), | |
$this->lerp($u, $this->grad($this->p[$AB+1], $x , $y-1, $z-1 ), | |
$this->grad($this->p[$BB+1], $x-1, $y-1, $z-1 )))); | |
return $result; | |
} | |
function fade($t) | |
{ | |
return $t * $t * $t * ( ( $t * ( ($t * 6) - 15) ) + 10); | |
} | |
function lerp($t, $a, $b) | |
{ | |
//Make a weighted interpolation between points | |
return $a + $t * ($b - $a); | |
} | |
function grad($hash, $x, $y, $z) | |
{ | |
// CONVERT LO 4 BITS OF HASH CODE INTO 12 GRADIENT DIRECTIONS | |
$h = $hash & 15; | |
$u = $h<8 ? $x : $y; | |
$v = $h<4 ? $y : ($h==12||$h==14 ? $x : $z); | |
return (($h&1) == 0 ? $u : -$u) + (($h&2) == 0 ? $v : -$v); | |
} | |
function random2D($x, $y) | |
{ | |
$x += $this->seed; | |
$y += $this->seed; | |
$value = 0.0; | |
$initialSize = $size = 3; | |
while ($size >= 1) { | |
$value += $this->smoothNoise($x*3 / $size, $y*3 / $size, 100 / $size); | |
$size--; | |
} | |
if ($value < -1) $value = -1; | |
if ($value > 1) $value = 1; | |
return $value; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment