2016-05-05 5 views
2

Я пытаюсь мою попытку Перлин шума (3-мерным), как указано в этом документе: http://lodev.org/cgtutor/randomnoise.htmlПерлин шума Попытка

Однако, это то, что я получаю. perlin noise attempt Похоже, что сглаживание не работает. Вы можете видеть блоки размером с параметром «размер». Может кто-то указать, что я делаю неправильно?

Вот мой код:

%ffp 

ctl(1):standard,"Size",range=(1,256), pos=(300,20), size=(120,*),val=64,track, action=preview 

onFilterStart: 
{ 
allocArray(9,64,64,64,4); // Array for noise depth 
    for(int z = 0; z < 64; z++) 
    for(int y = 0; y < 64; y++) 
    for(int x = 0; x < 64; x++) { 
    fputArray(9,x,y,z,(float)(rand() % 32768)/32768.0); 
    } 

return false; 
} 

forEveryTile: 
{ 
double fractX,fractY,fractZ,xx,yy,zz; 
int x1,y1,z1,x2,y2,z2,col; 
double value = 0.0, value2 = 0.0, size, isize=(float)ctl(1); 
// int X=screen Width, int Y=screen Height 

    for(int y = 0; y < Y; y++) { 
    for(int x = 0; x < X; x++) { 
    //for(int z = 0; z < 64; z++) { 
    value2 = 0.0; 
    size = isize; 

    while (size >=1.0) { 
    xx=(float)x/size; 
    yy=(float)y/size; 
    zz=(float)clock()/size; 
    fractX = xx - (int)(xx); 
    fractY = yy - (int)(yy); 
    fractZ = zz - (int)(zz); 
    x1 = ((int)(xx) + 64) % 64; 
    y1 = ((int)(yy) + 64) % 64; 
    z1 = ((int)(zz) + 64) % 64; 
    x2 = (x1 + 64- 1) % 64; 
    y2 = (y1 + 64- 1) % 64; 
    z2 = (z1 + 64- 1) % 64; 

    value=0.0; 
    value += fractX  * fractY  * fractZ  * fgetArray(9,z1,y1,x1); 
    value += fractX  * (1 - fractY) * fractZ  * fgetArray(9,z1,y2,x1); 
    value += (1 - fractX) * fractY  * fractZ  * fgetArray(9,z1,y1,x2); 
    value += (1 - fractX) * (1 - fractY) * fractZ  * fgetArray(9,z1,y2,x2); 

    value += fractX  * fractY  * (1 - fractZ) * fgetArray(9,z2,y1,x1); 
    value += fractX  * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x1); 
    value += (1 - fractX) * fractY  * (1 - fractZ) * fgetArray(9,z2,y1,x2); 
    value += (1 - fractX) * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x2); 

    value2 += value*size; 
    size /= 2.0; 
    } 

    col=(int)((float)(128.0 * value2/isize)); 
    col=max(min(col,255),0); 
    psetp(x,y,RGB(col,col,col)); 

//} //z 
} //x 
} //y 

return true; 
} 
+0

Какова мотивация использования 'clock()' as 'z' координат?Очевидно, что вы хотите создать облачную анимацию, но 'clock' может давать разные значения' z' для каждого прогона внутреннего цикла, что означает, что вы выполняете интерполяцию на разных кадрах анимации. Если «для каждой плитки» означает «для каждого« z », просто перечислите возможные значения« z ». –

+0

Это очень верно, но даже если я полностью выхожу из уравнения, я до сих пор получаю эти блочные результаты. Я зацикливал z на петлю, чтобы получить истинный трехмерный шум, но для отладки я взял его и превратил в двумерный цикл. Поэтому я не думаю, что причина является причиной проблемы. – Rich95

+0

Итак, результат является блочным даже для 2d-шума? –

ответ

1

Ваш код рода трудно читать, как написано.

Для шума Perlin начинаются с целочисленной функции шума, которая ведет себя как хэш.

float noise(int x, int y, int z) { return hash(x+y*5+z*7); } 

или

float noise(int x, int y, int z) { return array[x%w+y%h*w+z%d*w*h]; } 

Это только примеры. Важная часть состоит в том, что шум (x, y, z) = шум (x, y, z). Функция шума должна возвращать одно и то же значение для тех же параметров каждый раз.

Существует проблема: функция шумов принимает только целочисленные параметры! Но мы хотели бы попробовать его по значениям float.

float noisesample (float x, float y, float z) { ... } 

Самый простой способ использовать линейную фильтрацию. Любое положительное значение float находится между (int) pos и ((int) pos) +1. В подпозиции pos- (int) поз. Это заставляет нас:

float Lerp(float a, float b, float f) { return a+(b-a)*f; } 

где F является суб-позиции в [0..1] диапазоне и, Ь являются значения слева и справа. Если f равно 0, Lerp возвращает a, если оно равно 1, оно возвращает b. Между ними выполняется линейная интерполяция.

Так что используйте это для простой 1D noisesample функции:

float noisesample(float x) { return Lerp(noise((int)x), noise((int)x+1), fract(x) } 

с

float fract(float x) { return x-(int)x; } 

Я использую (INT) х свободно здесь, это то же самое, как пол (х), если х является положительным.

Чтобы перейти от одного параметра noisesample х, у легко: Сделайте Lerp дважды х в у и у + 1, и Lerp между тем:

float noisesample(float x, float y) { 
    float y0 = Lerp(noise((int)x,(int)y), noise((int)x+1,(int)y), fract(x) } 
    float y1 = Lerp(noise((int)x,(int)y+1), noise((int)x+1,(int)y+1), fract(x) } 
    return Lerp (y0, y1, fract(y)); 
} 

Первый интерполировать х, дважды, интерполировать между результатами в y. В целом мы измеряем шум() 4 раза. Я оставляю это как упражнение, как писать noiseample (float x, float y, float z). Он будет измерять шум() восемь раз и вызывает Lerp 7 раз.

Все, что досталось нам, это то, что мы можем пробовать шум (несколько гладкий - есть более плавные пути!) В поплавковых координатах. И это то, что нам нужно сделать perlin noise!

float perlin(float x, float y, float z, int oc=4) { 
    // maybe: x = x*2^oc, y, z... 
    float r = 0; 
    float s = 1; 
    for (int i=0; i<oc; i++) { 
     r += noisesample(x,y,z) * s; 
     s/=2.0f; // to taste 
     x/=2.0f; 
     y/=2.0f; 
     z/=2.0f; 
    } 
    return r; 
} 

Основная идея - понять выборку. Это всего лишь комбинация выборки простой функции целочисленного шума.