使用单纯形噪声替换的球体的解析法线

时间:2014-12-16 23:12:16

标签: opengl glsl normals simplex-noise

我想渲染一个像球体一样的行星。总体思路如下:

  • 生成一组构成球体的单位长度顶点。
  • 渲染球体时,着色器会评估单位球面上的3D单面噪声。
  • 结果用作"身高"沿着它的方向移动当前顶点。

到目前为止,一切都正常运作。

现在我想添加灯光,因此需要法线表面。

在实现与照明相关的部分时,我快速添加了一种方法,使用片段着色器中的偏导数来估计地形的法线,如下所示:

vec3 X = dFdx(ins.position);
vec3 Y = dFdy(ins.position);
vec3 normal = normalize(cross(X,Y));

其中ins.position是插值世界位置。

虽然这种方法有效,但它看起来并不是很好,因为它实际上会导致每个法线正常。

Bad normal approximation

现在回答实际问题:

  • 计算每顶点法线会导致平滑法线,与图片不同,是否正确?
  • 单因素噪声优于Perlin噪声的优点之一是它具有定义明确且连续的渐变,可以非常便宜地计算出来#34; (引用优秀的Simplex Noise demystified)并使用渐变应该能够计算正常,正确吗?

如果秒问题是"是"我有两个问题:

  • 单纯形噪声算法取自popular source,遗憾的是不包括梯度计算。我将在下面发布我的添加尝试,但我不知道它是否正确。
  • 即使我有渐变,我仍然坚持从那里获得法线。

非常感谢任何帮助!

我对渐变实现的镜头(替换了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);
}

更新

关于从梯度计算表面法线的部分已在此处回答: Surface normal to point on displaced sphere

现在剩下的问题是如何将梯度计算实现到3D Simplex Noise的GLSL版本中,因为我的实现似乎有问题。

更新2:

渐变计算似乎几乎正确,只是缩放似乎已关闭 除了乘以42,除以5得到相当好的结果,但这是通过反复试验找到的。适当的缩放因子会很好。

1 个答案:

答案 0 :(得分:2)

好吧,事实证明我的问题几乎与数学有关。

如果有人有兴趣:
问题中公布的梯度计算的GLSL实现是完全正确的 直接从梯度计算法线是可能的,如here所述。

结果看起来和我想要的一样,我很高兴;)

Smooth per-vertex normals