我想渲染一个像球体一样的行星。大体思路如下:
- 生成一组构成球体的单位长度顶点。
- 在渲染球体时,着色器会评估单位球体上的点处的 3D 单纯形噪声。
- 结果用作“高度”以沿其方向移动当前顶点。
到目前为止,一切都按预期进行。
现在我想添加光照,因此需要表面的法线。
在实现照明相关部分时,我快速添加了一种方法来使用片段着色器中的偏导数来估计地形的法线,如下所示:
vec3 X = dFdx(ins.position);
vec3 Y = dFdy(ins.position);
vec3 normal = normalize(cross(X,Y));
ins.position
插值的世界位置在哪里。
虽然这可行,但它看起来不是很好,因为它本质上会产生每个面的法线。
现在到实际问题:
- 与图片不同,计算每个顶点的法线会产生平滑的法线,对吗?
- Simplex Noise 优于 Perlin Noise 的优点之一是它具有“可以非常便宜地计算的所有地方的定义明确且连续的梯度”(引用优秀的Simplex Noise demystified)并且使用梯度应该能够计算正常,对吗?
如果第二个问题是“是”,我有两个问题:
- 单纯形噪声算法取自一个流行的来源,遗憾的是它不包括梯度计算。我将在下面发布我添加它的尝试,但我不知道它是否正确。
- 即使我有渐变,我也坚持从那里推导出法线。
任何帮助是极大的赞赏!
我对渐变实现的看法(替换了最后几行snoise):
float snoise(vec3 v, out vec3 grad)
{
......
// Mix final noise value
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
vec4 m2 = m * m;
vec4 m4 = m2 * m2;
vec4 pdotx = vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3));
vec4 temp = m2 * m * pdotx;
grad = -8.0 * (temp.x * x0 + temp.y * x1 + temp.z * x2 + temp.w * x3);
grad += m4.x * p0 + m4.y * p1 + m4.z * p2 + m4.w * p3;
grad *= 42.0;
return 42.0 * dot(m4, pdotx);
}
更新:
关于从梯度计算表面法线的部分已在此处得到解答: 表面法线到位移球上的点。
现在剩下的问题是如何将梯度计算实现到 3D Simplex Noise 的 GLSL 版本中,因为我的实现似乎有问题。
更新 2:
梯度计算似乎几乎是正确的,只是缩放似乎关闭了。
不是乘以 42,而是除以 5 会得到很好的结果,但这是通过反复试验发现的。适当的比例因子会很好。