本项目参考自《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)));
}
};