"块状" Perlin杂 [英] "Blocky" Perlin noise

查看:205
本文介绍了"块状" Perlin杂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在努力执行在C柏林噪声发生器(基于关闭肯培林的网站,使用SDL库作为屏幕输出),但输出显示,插块之间的边缘不连续或平滑 - 插值块做的真是块清单

I've recently been trying to implement a Perlin Noise generator in C (based off Ken Perlin's website, using the SDL library as a screen output), but the output shows that the edges between interpolation blocks are not continuous or smooth - the interpolation blocks do really manifest as blocks.

我试过4种插值的,所有的平稳的人看起来差不多的;只有余弦长相(非常)略好和线性直相比之下看起来可怕。 (下面是余弦和线性)
噪声与线性插值

I've tried four kinds of interpolations, and all the "smooth" ones look about the same; only cosine looks (very) slightly better and straight linear looks horrible by comparison. (below are Cosine and Linear)

讽刺的是,如果发出声音的碎片总和(我的这个最终目的),线性吹走顺利插在blockyness的条款,实际上看起来几乎罚款。

Ironically, if making a fractal sum of noises (my ultimate purpose of this), linear blows away the smooth interpolations in terms of "blockyness" and actually looks almost fine.

我是pretty肯定有我丢失的东西在我的code或做错了,但我似乎无法找到它。

I'm pretty sure that there's something I'm missing in my code or doing it wrong, but I can't seem to find it.

有关的参考,我目前的code以下:

For reference, my current code below:

#include<stdio.h>
#include<math.h>
#include<SDL/SDL.h>

void normalize3(float *vec3){
    float distX=0,distY=0,distZ=0;
    distX=vec3[0];
    distX*=distX;
    distY=vec3[1];
    distY*=distY;
    distZ=vec3[2];
    distZ*=distZ;
    float dist=sqrtf(distX+distY+distZ);
    vec3[0]/=dist;
    vec3[1]/=dist;
    vec3[2]/=dist;
}

float sinterpolate(float scale){
    //return scale*scale*(3.0-2*scale); //Classic 3*t^2-2*t^3

    /*float t=scale*scale;
    float u=t*t;
    return (6.0*u*scale-15.0*u+10.0*t*scale);*/ //Improved 6*t^5-15*t^4+10*t^3

    return (0.5-cosf(scale*M_PI)/2.0); //Straight cosine interpolation
}

float linterpolate(float a,float b,float scale){
    return a+scale*(b-a);
}

float noise3(float *vec3,float *grads,Uint8 *perms){
    vec3[0]=fmodf(vec3[0],256.0);
    vec3[1]=fmodf(vec3[1],256.0);
    vec3[2]=fmodf(vec3[2],256.0);
    Uint8 ivec3[3];

    float relPos[3],temp;
    float cube[2][2][2];
    Uint8 index;

    //One loop for each dimension of noise.
    for(int x=0;x<2;x++){
        ivec3[0]=vec3[0];
        ivec3[0]+=x;
        relPos[0]=vec3[0]-ivec3[0];
        for(int y=0;y<2;y++){
            ivec3[1]=vec3[1];
            ivec3[1]+=y;
            relPos[1]=vec3[1]-ivec3[1];
            for(int z=0;z<2;z++){
                ivec3[2]=vec3[2];
                ivec3[2]+=z;
                relPos[2]=vec3[2]-ivec3[2];

                index=ivec3[0]+perms[ivec3[1]+perms[ivec3[2]]];

                temp=relPos[0]*grads[3*index];
                temp+=relPos[1]*grads[3*index+1];
                temp+=relPos[2]*grads[3*index+2]; //The gradient's dot product
                                                  //with respect to the point
                                                  //being analyzed

                cube[x][y][z]=temp;
            }
        }
    }

    ivec3[0]--;
    ivec3[1]--;
    ivec3[2]--;
    relPos[0]=vec3[0]-ivec3[0];
    relPos[1]=vec3[1]-ivec3[1];
    relPos[2]=vec3[2]-ivec3[2];
    relPos[0]=sinterpolate(relPos[0]);  //Comment these
    relPos[1]=sinterpolate(relPos[1]);  //if you want
    relPos[2]=sinterpolate(relPos[2]);  //Linear Interpolation.


    return linterpolate(linterpolate(linterpolate(cube[0][0][0],cube[0][0][1],relPos[2]),linterpolate(cube[0][8][0], cube[0][9][1],relPos[2]),relPos[1]),linterpolate(linterpolate(cube[1][0][0],cube[1][0][1],relPos[2]),linterpolate(cube[1][10][0], cube[1][11][1],relPos[2]),relPos[1]),relPos[0]);
}

int main(int argc,char **args){
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Surface *screen=SDL_SetVideoMode(512,512,32,SDL_SWSURFACE);
    srandom(SDL_GetTicks());  //If not on OSX/BSD, use srand()
    Uint32 *pixels;
    Uint32 grays[256];
    for(int x=0;x<256;x++){
        grays[x]=SDL_MapRGB(screen->format,x,x,x);
    }


    float grads[768];
    Uint8 perms[256];
    //First, generate the gradients and populate the permutation indexes.
    for(int x=0;x<256;x++){
        grads[3*x]=random();    //If not on OSX/BSD, use rand()
        grads[3*x+1]=random();
        grads[3*x+2]=random();
        normalize3(grads+3*x);

        perms[x]=x;
    }

    //Let's scramble those indexes!
    for(int x=0;x<256;x++){
        Uint8 temp=perms[x];
        Uint8 index=random();
        perms[x]=perms[index];
        perms[index]=temp;
    }

    printf("Permutation Indexes: ");
    for(int x=0;x<256;x++){
        printf("%hhu, ",perms[x]);
    }
    putchar('\n');

    Uint32 timer=SDL_GetTicks(),frameDelta;
    SDL_Event eventos;
    float zoom=-5.0;
    eventos.type=SDL_NOEVENT;
    while(eventos.type!=SDL_QUIT){
        SDL_PollEvent(&eventos);
        if(SDL_GetKeyState(NULL)[SDLK_UP]){
            zoom-=0.001*frameDelta;
        }
        else if(SDL_GetKeyState(NULL)[SDLK_DOWN]){
            zoom+=0.001*frameDelta;
        }
        float scale=expf(zoom);
        pixels=screen->pixels;
        float pos[3];
        pos[2]=SDL_GetTicks()/3000.0;
        for(int y=0;y<512;y++){
            pos[1]=y*scale;
            for(int x=0;x<512;x++){
                pos[0]=x*scale;
                float fracPos[3];
                fracPos[0]=pos[0];
                fracPos[1]=pos[1];
                fracPos[2]=pos[2];
                float color=noise3(fracPos,grads,perms);

                //Fractal sums of noise, if desired
                /*fracPos[0]*=2.0;
                fracPos[1]*=2.0;
                fracPos[2]*=2.0;
                color+=noise3(fracPos,grads,perms)/2.0;

                fracPos[0]*=2.0;
                fracPos[1]*=2.0;
                fracPos[2]*=2.0;
                color+=noise3(fracPos,grads,perms)/4.0;

                fracPos[0]*=2.0;
                fracPos[1]*=2.0;
                fracPos[2]*=2.0;
                color+=noise3(fracPos,grads,perms)/8.0;

                fracPos[0]*=2.0;
                fracPos[1]*=2.0;
                fracPos[2]*=2.0;
                color+=noise3(fracPos,grads,perms)/16.0;

                */

                *pixels++=grays[127+(Sint8)(256.0*color)];
            }
        }

        SDL_Flip(screen);
        frameDelta=SDL_GetTicks()-timer;
        printf("Running @ %.3f FPS!\n",1000.0/frameDelta);
        if(frameDelta<16){
            SDL_Delay(16-frameDelta);
        }
        timer=SDL_GetTicks();
    }

    return 0;
}

使用方法:在运行时,preSS并按住向上或向下放大或缩小噪声网格

Usage: While running, press and hold Up or Down to magnify or shrink the noise grid.

推荐答案

我终于发现了问题:梯度发生器

I have finally found the problem: the gradient generator.

我是假设随机()函数将其二进制值传递给毕业生[]数组,覆盖浮点数的方式的整个范围。不幸的是,情况并非如此:它的返回值正在先转换成浮点数,则存放在数组中为止。我的这个最大的问题是,所有产生的向量了积极的成员值

I was assuming that the random() function would pass its binary value to the grads[] array, covering the whole range of floating point numbers in the way. Unfortunately, that was not the case: its return value was being converted first into a float, then stored in the array. My biggest issue with this was that all generated vectors had positive member values.

这正当块文物:有大量相邻的生成小山(高值),但没有谷(低值),并且两个相邻的山头最终将发生冲突并产生沿该线整数值。

This justified the block artifacts: there were lots of "hills" (high values) being generated next to each other, but no "valleys" (low values), and two adjacent hills would eventually clash and generate the lines along the integer values.

意识到这一点后,我试着做一些杂耍的指针,并直接在UINT32形式存储的值,但在梯度值变得古怪(INF文件,NaN的,1.0秒和0.0秒一路),所以我回来了原来的路线和否定在$ C $的数字C本身。

After realizing this, I tried to do some pointer juggling and storing the values directly in Uint32 form, but the values in the gradients became wacky (infs, NaNs, 1.0s and 0.0s all the way), so I came back to the original route and negated the numbers in the code itself.

这7班轮解决整个问题:

This 7-liner solved the whole problem:

int y=random()&7;
if(y&1)
    grads[3*x]*=-1.0f;
if(y&2)
    grads[3*x+1]*=-1.0f;
if(y&4)
    grads[3*x+2]*=-1.0f;

只需将它之前或正火功能后的它的完成

现在的它看起来像柏林噪声:

Now it looks like Perlin Noise:

和分形之和也看起来好一点。

And the fractal sum also looks a bit better:

@DiJuMx:我以前见过的改善噪音纸,但没有意识到梯度会多少影响到噪音的外观。另外,通过试图改变坐标空间从0〜256 0〜1导致碎片总和不工作了,得到的图像具有相同的块伪影。

@DiJuMx: I've seen the "Improving Noise" paper before, but hadn't realized how much the gradients would affect the noise appearance. Also, by trying to change the coordinate space from 0~256 to 0~1 resulted in the fractal sum not working anymore, and the resulting image had the same block artifacts.

这篇关于&QUOT;块状&QUOT; Perlin杂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆