《用一週學習光線追蹤》4.柏林噪聲

本項目參考自《Ray Tracing in One Weekend》系列
上接《用兩天學習光線追蹤》,繼續學習光線追蹤。
項目鏈接:https://github.com/maijiaquan/ray-tracing-with-imgui

目錄:
《用兩天學習光線追蹤》1.項目介紹和ppm圖片輸出
《用兩天學習光線追蹤》2.射線、簡單相機和背景輸出
《用兩天學習光線追蹤》3.球體和表面法向量
《用兩天學習光線追蹤》4.封裝成類
《用兩天學習光線追蹤》5.抗鋸齒
《用兩天學習光線追蹤》6.漫反射材質
《用兩天學習光線追蹤》7.反射向量和金屬材質
《用兩天學習光線追蹤》8.折射向量和電介質
《用兩天學習光線追蹤》9.可放置相機
《用兩天學習光線追蹤》10.散焦模糊

《用一週學習光線追蹤》1.動態模糊
《用一週學習光線追蹤》2.BVH樹、AABB相交檢測
《用一週學習光線追蹤》3.純色紋理和棋盤紋理
《用一週學習光線追蹤》4.柏林噪聲
《用一週學習光線追蹤》5.球面紋理貼圖
《用一週學習光線追蹤》6.光照和軸對齊矩形
《用一週學習光線追蹤》7.長方體和平移旋轉


這一節生成柏林噪聲的原理還沒有徹底弄懂,僅僅是把代碼跑通了而已。
不過這一節並不影響整一章的學習,等以後有時間了,徹底搞懂之後,再回來填坑。


隨機生成噪聲:

class perlin {
    public:
        float noise(const vec3& p) const {
            int i = (int)floor(p.x()) &255;
            int j = (int)floor(p.y()) &255;
            int k = (int)floor(p.z()) &255;
            // return ranfloat[perm_x[i] ^ perm_y[j] ^ perm_z[k]];
            return get_ranfloat(i,j,k);
        }
        
        float get_ranfloat(int x, int y, int z) const {
            return ranfloat[perm_x[x & 255] ^ perm_y[y & 255] ^ perm_z[z & 255]];
        }
        static float *ranfloat;
        static int *perm_x;
        static int *perm_y;
        static int *perm_z;
};

static float* perlin_generate() {
    float * p = new float[256];
    for (int i = 0; i < 256; ++i)
        p[i] = random_double();
    return p;
}

void permute(int *p, int n) {
    for (int i = n-1; i > 0; i--) {
        int target = int(random_double()*(i+1));
        int tmp = p[i];
        p[i] = p[target];
        p[target] = tmp;
    }
    return;
}

static int* perlin_generate_perm() {
    int * p = new int[256];
    for (int i = 0; i < 256; i++)
        p[i] = i;
    permute(p, 256);
    return p;
}

float *perlin::ranfloat = perlin_generate();
int *perlin::perm_x = perlin_generate_perm();
int *perlin::perm_y = perlin_generate_perm();
int *perlin::perm_z = perlin_generate_perm();

class noise_texture : public texture {
    public:
        noise_texture() {}
        virtual vec3 value(float u, float v, const vec3& p) const {
            return vec3(1,1,1) * noise.noise(p);
        }
        perlin noise;
};

hittable *two_perlin_spheres() {
    texture *pertext = new noise_texture();
    hittable **list = new hittable*[2];
    list[0] = new sphere(vec3(0,-1000, 0), 1000, new lambertian(pertext));
    list[1] = new sphere(vec3(0, 2, 0), 2, new lambertian(pertext));
    return new hittable_list(list, 2);
}

效果如下:

加上三線性插值

inline float trilinear_interp(float c[2][2][2], float u, float v, float w) {
    float accum = 0;
    for (int i=0; i < 2; i++)
        for (int j=0; j < 2; j++)
            for (int k=0; k < 2; k++)
                accum += (i*u + (1-i)*(1-u))*
                         (j*v + (1-j)*(1-v))*
                         (k*w + (1-k)*(1-w))*c[i][j][k];

    return accum;
}

class perlin {
    public:
        float noise(const vec3& p) const {
            float u = p.x() - floor(p.x());
            float v = p.y() - floor(p.y());
            float w = p.z() - floor(p.z());
            int i = floor(p.x());
            int j = floor(p.y());
            int k = floor(p.z());
            float c[2][2][2];   //得到 以(i,j,k)爲左下角 的一個cube
            for (int di=0; di < 2; di++)
                for (int dj=0; dj < 2; dj++)
                    for (int dk=0; dk < 2; dk++)
                        // c[di][dj][dk] = ranfloat[perm_x[(i + di) & 255] ^ perm_y[(j + dj) & 255] ^ perm_z[(k + dk) & 255]];
                        c[di][dj][dk] = get_ranfloat(i + di, j + dj, k + dk);
                        
            return trilinear_interp(c, u, v, w);
        }

        float get_ranfloat(int x, int y, int z) const {
            return ranfloat[perm_x[x & 255] ^ perm_y[y & 255] ^ perm_z[z & 255]];
        }

        static float *ranfloat;
        static int *perm_x;
        static int *perm_y;
        static int *perm_z;
};

效果如下:

加多3行,更平滑

class perlin {
    public:
        float noise(const vec3& p) const {
            float u = p.x() - floor(p.x());
            float v = p.y() - floor(p.y());
            float w = p.z() - floor(p.z());
            u = u*u*(3-2*u);
            v = v*v*(3-2*v);
            w = w*w*(3-2*w);
            int i = floor(p.x());
            int j = floor(p.y());
            int k = floor(p.z());
            float c[2][2][2];   //得到 以(i,j,k)爲左下角 的一個cube
            for (int di=0; di < 2; di++)
                for (int dj=0; dj < 2; dj++)
                    for (int dk=0; dk < 2; dk++)
                        c[di][dj][dk] = get_ranfloat(i + di, j + dj, k + dk);
                        
            return trilinear_interp(c, u, v, w);
        }

        float get_ranfloat(int x, int y, int z) const{
            return ranfloat[perm_x[x & 255] ^ perm_y[y & 255] ^ perm_z[z & 255]];
        }

        static float *ranfloat;
        static int *perm_x;
        static int *perm_y;
        static int *perm_z;
};

修改noise_texture使得紋理縮放指定倍數:

class noise_texture : public texture {
    public:
        noise_texture() {}
        noise_texture(float sc) : scale(sc) {}
        virtual vec3 value(float u, float v, const vec3& p) const {
            return vec3(1, 1, 1) * noise.noise(scale * p);
        }
        float scale;
        perlin noise;
};

hittable *two_perlin_spheres() {
    texture *pertext = new noise_texture(4);
  	...
}

柏林噪聲

class noise_texture : public texture {
    public:
    		...
        virtual vec3 value(float u, float v, const vec3& p) const {
            return vec3(1,1,1)*noise.turb(scale * p);
        }
};

加上sin函數

class noise_texture : public texture {
    public:
        ...
        virtual vec3 value(float u, float v, const vec3& p) const {
            return vec3(1, 1, 1) * 0.5 * (1 + sin(scale * p.z() + 10 * noise.turb(p)));
        }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章