Skip to content

Instantly share code, notes, and snippets.

@BlackScorp
Created April 17, 2020 13:54
Show Gist options
  • Save BlackScorp/e720ad3dbc6c276aad6049be4ef55e1c to your computer and use it in GitHub Desktop.
Save BlackScorp/e720ad3dbc6c276aad6049be4ef55e1c to your computer and use it in GitHub Desktop.
perlin
<?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);
<?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;
}
}
<?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