Почему мой перлин-шум создает значения, выходящие за пределы ожидаемого диапазона, и создает неповторяющиеся плитки с твердыми краями? - PullRequest
1 голос
/ 20 января 2020

Итак, я написал свою реализацию перлинового шума php (код в конце) на основе https://flafla2.github.io/2014/08/09/perlinnoise.html, и я получаю странные результаты.

Подводя итог, здесь представляет собой изображение градаций серого для x и y между 0 и 5, полученное путем сопоставления каждого значения между 0 и 1 со значением между 0x0 и 0xFF и повторения его трижды. Кроме того, значение усечено, чтобы быть на безопасной стороне.

perlin weirdness

Первое, что следует заметить в этой предполагаемой шкале серого, - это не на самом деле оттенки серого. Цвета действительны из-за усечения. Тем не менее, цветные и белые пятна существуют , поскольку значения находятся не между 0 и 1, а (в данном случае) между -21.807741342341 и 20.055290825771 (полученными из той же программы).

Исходя из того, что я видел при отладке этой вещи ранее, я бы предположил, что цвета больше 1, а белые отрицательны (также, когда я добавляю abs() к коду, я избавляюсь от всего чистого белые области).

Из того, что я понимаю о перлин-шуме, он должен быть непрерывным. Не с этими линиями, нарисованными там, где x или y является точной единицей.

Кроме того, в комментариях к учебнику говорится, что возвращаемые значения никогда не должны превышать границу [0,1]. Очевидно, это так. Что здесь происходит? Не то, чтобы мне не нравились эти паттерны или что-то в этом роде, но я думаю, что с помощью рабочего перлин-шума можно, вероятно, получить нечто подобное.

Примечание. путь возможен. Пожалуйста, не жалуйтесь.

<?php

class perlin{
    public function __construct(){
        $this->p=array_merge($this->permutation,$this->permutation);
        //print_r($this->p);
    }

    private $permutation=array(93, 127, 136, 113, 54, 147, 1, 165, 82, 43, 7, 125, 149, 244, 192, 100, 48, 39, 96, 98, 255, 60, 22, 158, 171, 137, 23, 72, 142, 166, 11, 94, 92, 87, 139, 247, 111, 236, 61, 188, 86, 250, 151, 9, 14, 90, 8, 124, 180, 179, 157, 17, 141, 209, 35, 242, 42, 184, 186, 172, 21, 215, 162, 227, 74, 121, 177, 253, 214, 220, 66, 230, 109, 46, 239, 119, 175, 238, 19, 6, 95, 15, 229, 190, 226, 26, 88, 182, 106, 76, 27, 49, 212, 213, 25, 89, 56, 219, 205, 164, 83, 38, 146, 5, 102, 170, 115, 181, 103, 228, 211, 31, 155, 197, 232, 204, 52, 199, 173, 148, 101, 85, 153, 156, 3, 224, 47, 33, 208, 150, 114, 116, 129, 145, 50, 160, 183, 140, 36, 217, 185, 233, 132, 107, 135, 75, 221, 191, 223, 81, 32, 10, 243, 18, 65, 246, 248, 78, 176, 225, 131, 55, 29, 80, 99, 16, 71, 112, 163, 62, 123, 51, 195, 251, 178, 67, 44, 105, 159, 30, 104, 174, 4, 152, 57, 133, 252, 45, 120, 256, 207, 70, 202, 201, 68, 189, 84, 169, 53, 254, 168, 12, 59, 249, 206, 63, 200, 128, 37, 77, 108, 64, 28, 122, 196, 167, 91, 117, 231, 187, 34, 69, 41, 110, 241, 40, 154, 237, 73, 143, 58, 245, 20, 234, 235, 222, 97, 210, 193, 161, 203, 216, 118, 24, 126, 194, 79, 218, 2, 13, 138, 130, 134, 240, 144, 198);
    //generated by seq 1 256|shuf|sed 's/$/,/g'|tr '\n' ' '

    public $repeat=0;

    private $p=array();

    private function inc($num){
        $num++;
        if($this->repeat>0){
            $num%=$this->repeat;
        }
        return $num;
    }

    private function fade(float $t){
        return $t*$t*$t*($t*($t*6+15)+10);
    }

    public function perlin(float $x,float $y,float $z){
        if($this->repeat>0){
            $x=$x%$this->repeat;
            $y=$y%$this->repeat;
            $z=$z%$this->repeat;
        }
        $xi=(int)($x) & 255;
        $yi=(int)($y) & 255;
        $zi=(int)($z) & 255;
        $xf=$x-(int)($x);
        $yf=$y-(int)($y);
        $zf=$z-(int)($z);

        //echo "$xi $yi $zi $xf $yf $zf<br>\n\n";

        $u=$this->fade($xf);
        $v=$this->fade($yf);
        $w=$this->fade($zf);

        $aaa=$this->p[$this->p[$this->p[           $xi ]+           $yi ]+           $zi ];
        $aba=$this->p[$this->p[$this->p[           $xi ]+$this->inc($yi)]+           $zi ];
        $aab=$this->p[$this->p[$this->p[           $xi ]+           $yi ]+$this->inc($zi)];
        $abb=$this->p[$this->p[$this->p[           $xi ]+$this->inc($yi)]+$this->inc($zi)];
        $baa=$this->p[$this->p[$this->p[$this->inc($xi)]+           $yi ]+           $zi ];
        $bba=$this->p[$this->p[$this->p[$this->inc($xi)]+$this->inc($yi)]+           $zi ];
        $bab=$this->p[$this->p[$this->p[$this->inc($xi)]+           $yi ]+$this->inc($zi)];
        $bbb=$this->p[$this->p[$this->p[$this->inc($xi)]+$this->inc($yi)]+$this->inc($zi)];

        $x1=$this->lerp($this->grad($aaa,$xf,$yf,$zf),
                        $this->grad($baa,$xf-1,$yf,$zf),$u);
        $x2=$this->lerp($this->grad($aba,$xf,$yf-1,$zf),
                        $this->grad($bba,$xf-1,$yf-1,$zf),$u);
        $y1=$this->lerp($x1,$x2,$v);

        $x1=$this->lerp($this->grad($aab,$xf,$yf,$zf-1),
                        $this->grad($bab,$xf-1,$yf,$zf-1),$u);
        $x2=$this->lerp($this->grad($abb,$xf,$yf-1,$zf-1),
                        $this->grad($bbb,$xf-1,$yf-1,$zf-1),$u);
        $y2=$this->lerp($x1,$x2,$v);

        return ($this->lerp($y1,$y2,$w)+1)/2;
    }



    private function grad(int $hash,float $x,float $y,float $z){
        switch($hash & 0xF){
            case 0x0: return $x+$y;
            case 0x1: return -$x + $y;
            case 0x2: return  $x - $y;
            case 0x3: return -$x - $y;
            case 0x4: return  $x + $z;
            case 0x5: return -$x + $z;
            case 0x6: return  $x - $z;
            case 0x7: return -$x - $z;
            case 0x8: return  $y + $z;
            case 0x9: return -$y + $z;
            case 0xA: return  $y - $z;
            case 0xB: return -$y - $z;
            case 0xC: return  $y + $x;
            case 0xD: return -$y + $z;
            case 0xE: return  $y - $x;
            case 0xF: return -$y - $z;
            default: return 0;
        }
    }

    private function lerp(float $a,float $b,float $x){
        return $a+$x*($b-$a);
    }

}
?>

Минимальный пример недопустимого значения:

<?php 
require("perlin.php");
$noise=new perlin;

echo $noise->perlin(1.5,0.5,0);        //return 1.4375
?>

1 Ответ

1 голос
/ 21 января 2020

Вы переключили знак в вашей функции fade. У вас есть 6+15, где оно должно быть 6-15.

public static double fade(double t) {
    return t * t * t * (t * (t * 6 - 15) + 10);         // 6t^5 - 15t^4 + 10t^3
}

После этого изменения я получаю

$noise->perlin(1.5,0.5,0); // 0.5
...