Error message here!

Hide Error message here!

Error message here!

Hide Error message here!

Error message here!

Close

# 【Ray Tracing The Next Week 超详解】 光线追踪2-4 Perlin noise

Preface

还有一些其他的图

Chapter 4：Perlin Noise

关于随机数：

```class Perlin
{
public:
inline rtvar noise(const rtvec& p)const;
inline static rtvar* randomvalue() { return _randomvalue; }
inline static int* perm_x() { return _perm_x; }
inline static int* perm_y() { return _perm_y; }
inline static int* perm_z() { return _perm_z; }
public:
static rtvar* perlin_generate();
static int* perlin_generate_perm();
static void permute(int* p, int n);private:
static rtvar* _randomvalue;
static int* _perm_x;
static int* _perm_y;
static int* _perm_z;
};```

```rtvar * Perlin::perlin_generate()
{
rtvar* p = new rtvar[256];
for (int i = 0; i < 256; ++i) p[i] = lvgm::rand01();
return p;
}
int* Perlin::perlin_generate_perm()
{
int * p = new int[256];
for (int i = 0; i < 256; ++i) p[i] = i;
permute(p, 256);
return p;
}
void Perlin::permute(int * p, int n)
{
for (int i = n - 1; i > 0; --i)
{
int target = int(lvgm::rand01() * (i + 1));
stds swap(p[i], p[target]);
}
}```

```rtvar* Perlin::_randomvalue = Perlin::perlin_generate();
int* Perlin::_perm_x = Perlin::perlin_generate_perm();
int* Perlin::_perm_y = Perlin::perlin_generate_perm();
int* Perlin::_perm_z = Perlin::perlin_generate_perm();```

u，v，w是插值时候用的，目前暂时不用

```class noise_texture :public texture
{
public:
noise_texture() { }
virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override;
private:
Perlin _noise;
};
rtvec noise_texture::value(rtvar u, rtvar v, const rtvec& p)const
{
return rtvec(1, 1, 1) * _noise.noise(p);
}```

`return _randomvalue[_perm_x[i] ^ _perm_y[i] ^ _perm_z[i]];`

```rtvar Perlin::trilinear_interp(rtvar c[2][2][2], rtvar u, rtvar v, rtvar w)
{
rtvar accumulate = 0;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
accumulate +=
(i * u + (1 - i)*(1 - u))*
(j * v + (1 - j)*(1 - v))*
(k * w + (1 - k)*(1 - w))*
c[i][j][k];
return accumulate;
}```

```inline rtvar Perlin::noise(const rtvec& p)const
{
int i = floor(p.x());
int j = floor(p.y());
int k = floor(p.z());
rtvar u = p.x() - i;
rtvar v = p.y() - j;
rtvar w = p.z() - k;
rtvar list[2][2][2];
for (int a = 0; a < 2; ++a)
for (int b = 0; b < 2; ++b)
for (int c = 0; c < 2; ++c)
list[a][b][c] = _randomvalue[_perm_x[(i + a) & 255] ^ _perm_y[(j + b) & 255] ^ _perm_z[(k + c) & 255]];
return trilinear_interp(list, u, v, w);
}```

我们还可以再尝试一下利用Hermit Cubic来进行舍入插值

```class noise_texture :public texture
{
public:
noise_texture() { }
noise_texture(const rtvar scale);
virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override;
private:
Perlin _noise;
rtvar _scale;
};
noise_texture::noise_texture(const rtvar scale)
:_scale(scale)
{
}
rtvec noise_texture::value(rtvar u, rtvar v, const rtvec& p)const
{
return rtvec(1, 1, 1) * _noise.noise(_scale * p);
}```

```rtvec * Perlin::_randomvalue = Perlin::perlin_generate();
int * Perlin::_perm_x = Perlin::perlin_generate_perm();
int * Perlin::_perm_y = Perlin::perlin_generate_perm();
int * Perlin::_perm_z = Perlin::perlin_generate_perm();```

```rtvec * Perlin::perlin_generate()
{
rtvec * p = new rtvec[256];
for (int i = 0; i < 256; ++i)
p[i] = rtvec(-1 + 2 * lvgm::rand01(), -1 + 2 * lvgm::rand01(), -1 + 2 * lvgm::rand01()).ret_unitization();
return p;
}```

且看上面这段代码， -1 + 2*lvgm::rand01()，返回的区间为-1~1

```inline rtvar Perlin::noise(const rtvec& p)const
{
int i = floor(p.x());
int j = floor(p.y());
int k = floor(p.z());
rtvar u = p.x() - i;
rtvar v = p.y() - j;
rtvar w = p.z() - k;
rtvec list[2][2][2];
for (int a = 0; a < 2; ++a)
for (int b = 0; b < 2; ++b)
for (int c = 0; c < 2; ++c)
{
list[a][b][c] = _randomvalue[_perm_x[(i + a) & 255], _perm_y[(j + b) & 255], _perm_z[(k + c) & 255]];
#ifdef listtest
if (list[a][b][c].x() < 0)stds cout << "list.x < 0 " << stds endl;
if (list[a][b][c].y() < 0)stds cout << "list.y < 0 " << stds endl;
if (list[a][b][c].z() < 0)stds cout << "list.z < 0 " << stds endl;
#endif
}
return perlin_interp(list, u, v, w);```

```rtvar Perlin::perlin_interp(rtvec list[2][2][2], rtvar u, rtvar v, rtvar w)
{
rtvar uu = u*u*(3 - 2 * u);
rtvar vv = v*v*(3 - 2 * v);
rtvar ww = w*w*(3 - 2 * w);
rtvar accumulate = 0;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
{
rtvec weight(u - i, v - j, w - k);
accumulate +=
(i*uu + (1 - i) * (1 - uu))*
(j*vv + (1 - j) * (1 - vv))*
(k*ww + (1 - k) * (1 - ww))*
lvgm::dot(list[i][j][k], weight);
#ifdef accumulatetest
if (accumulate < 0)stds cout << "accumulate < 0 " << stds endl;
#endif
}
return (accumulate);
}```

****************************** 为什么是“错”的 ***************************************

如果noise返回一个负值，那么

```rtvec noise_texture::value(rtvar u, rtvar v, const rtvec& p)const
{
return rtvec(1., 1., 1.) *_noise.noise(p);
}```

```bool lambertian::scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const
{
rtvec target = info._p + info._n + lvgm::random_unit_sphere();
scattered = ray{ info._p, target - info._p };
attenuation = _albedo->value(0.,0.,info._p);
return true;
}```

scatter传出去的attenuation就是负值

gamma校正负值开根号为出现无穷

****************************** 插曲结束 ***************************************

```rtvec * Perlin::perlin_generate()
{
rtvec * p = new rtvec[256];
for (int i = 0; i < 256; ++i)
p[i] = rtvec(abs(-1 + 2 * lvgm::rand01()), abs(-1 + 2 * lvgm::rand01()), abs(-1 + 2 * lvgm::rand01())).ret_unitization();
return p;
}```

```rtvar Perlin::perlin_interp(rtvec list[2][2][2], rtvar u, rtvar v, rtvar w)
{
rtvar uu = u*u*(3 - 2 * u);
rtvar vv = v*v*(3 - 2 * v);
rtvar ww = w*w*(3 - 2 * w);
rtvar accumulate = 0;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
{
rtvec weight(u - i, v - j, w - k);
accumulate +=
(i*uu + (1 - i) * (1 - uu))*
(j*vv + (1 - j) * (1 - vv))*
(k*ww + (1 - k) * (1 - ww))*
lvgm::dot(list[i][j][k], weight);
#ifdef accumulatetest
if (accumulate < 0)stds cout << "accumulate < 0 " << stds endl;
#endif
}
return abs(accumulate); //!!!
}```

```/// Perlin.hpp
// -----------------------------------------------------
// [author] lv
// [begin ] 2019.1
// [brief ] the Perlin-class for the ray-tracing project
// from the 《ray tracing the next week》
// -----------------------------------------------------
#pragma once
namespace rt
{
class Perlin
{
public:
inline rtvar noise(const rtvec& p)const;
inline rtvar turb(const rtvec& p, int depth) const;
inline rtvec* randomvalue()const { return _randomvalue; }
inline int* perm_x()const { return _perm_x; }
inline int* perm_y()const { return _perm_y; }
inline int* perm_z()const { return _perm_z; }
public:
static rtvec * perlin_generate();
static void permute(int * p, int n);
static int * perlin_generate_perm();
static rtvar perlin_interp(rtvec list[2][2][2], rtvar u, rtvar v, rtvar w);
private:
static rtvec * _randomvalue;
static int * _perm_x;
static int * _perm_y;
static int * _perm_z;
};
rtvec * Perlin::_randomvalue = Perlin::perlin_generate();
int * Perlin::_perm_x = Perlin::perlin_generate_perm();
int * Perlin::_perm_y = Perlin::perlin_generate_perm();
int * Perlin::_perm_z = Perlin::perlin_generate_perm();
rtvec * Perlin::perlin_generate()
{
rtvec * p = new rtvec[256];
for (int i = 0; i < 256; ++i)
p[i] = rtvec(-1 + 2 * lvgm::rand01(), -1 + 2 * lvgm::rand01(), -1 + 2 * lvgm::rand01()).ret_unitization();
return p;
}
int* Perlin::perlin_generate_perm()
{
int * p = new int[256];
for (int i = 0; i < 256; ++i) p[i] = i;
permute(p, 256);
return p;
}
void Perlin::permute(int* p, int n)
{
for (int i = n - 1; i; i--)
{
int tar = int(lvgm::rand01() * (i + 1));
stds swap(p[i], p[tar]);
}
}
rtvar Perlin::turb(const rtvec& p, int depth = 7) const
{
rtvar accumulate = 0;
rtvec t = p;
rtvar weight = 1.0;
for (int i = 0; i < depth; i++)
{
accumulate += weight*noise(t);
weight *= 0.5;
t *= 2;
}
return abs(accumulate);
}
inline rtvar Perlin::noise(const rtvec& p)const
{
int i = floor(p.x());
int j = floor(p.y());
int k = floor(p.z());
rtvar u = p.x() - i;
rtvar v = p.y() - j;
rtvar w = p.z() - k;
rtvec list[2][2][2];
for (int a = 0; a < 2; ++a)
for (int b = 0; b < 2; ++b)
for (int c = 0; c < 2; ++c)
{
list[a][b][c] = _randomvalue[_perm_x[(i + a) & 255] ^ _perm_y[(j + b) & 255] ^ _perm_z[(k + c) & 255]];
#ifdef listtest
if (list[a][b][c].x() < 0)stds cout << "list.x < 0 " << stds endl;
if (list[a][b][c].y() < 0)stds cout << "list.y < 0 " << stds endl;
if (list[a][b][c].z() < 0)stds cout << "list.z < 0 " << stds endl;
#endif
}
return perlin_interp(list, u, v, w);
}
rtvar Perlin::perlin_interp(rtvec list[2][2][2], rtvar u, rtvar v, rtvar w)
{
#ifdef uvwtest
if (u < 0)stds cout << "u < 0 " << stds endl;
if (v < 0)stds cout << "v < 0 " << stds endl;
if (w < 0)stds cout << "w < 0 " << stds endl;
if (u > 1)stds cout << "u > 1 " << stds endl;
if (v > 1)stds cout << "v > 1 " << stds endl;
if (w > 1)stds cout << "w > 1 " << stds endl;
#endif
rtvar uu = u*u*(3 - 2 * u);
rtvar vv = u*v*(3 - 2 * v);
rtvar ww = u*w*(3 - 2 * w);
rtvar accumulate = 0;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
{
rtvec weight(u - i, v - j, w - k);
accumulate +=
(i*uu + (1 - i) * (1 - uu))*
(j*vv + (1 - j) * (1 - vv))*
(k*ww + (1 - k) * (1 - ww))*
lvgm::dot(list[i][j][k], weight);
#ifdef accumulatetest
if (accumulate < 0)stds cout << "accumulate < 0 " << stds endl;
#endif
}
return accumulate;
}
}```
Perlin.hpp

以及noise_texture.hpp中的value函数，如下：

同样，我们可以将光线追踪提高图片质量的惯用伎俩——采样，用在噪声值生成上面，即：使用具有多个相加频率的复合噪声。 这通常称为turbulence

_scale 为 5 时候

y = sin(wx + φ)

_scale就是w值，我实在调不出来书上的纹理

我把_scale的值调成6.3，结果如下：

_scale 值越大，图像上的正弦曲线波动幅度越小

https://www.cnblogs.com/lv-anchoret/p/10291292.html

30万现金开奖等你来领