opengl - 从 3D 噪声计算每顶点法线

标签 opengl glsl noise perlin-noise normals

我目前在 GLSL 中实现了一个 3D 噪声函数,该函数用于置换球体的顶点以给出地形。我目前正在使用几何着色器来简单地计算每个面的法线(我也有曲面分割,因此为什么我在这里这样做而不是顶点着色器)。现在我想计算每个顶点的法线。

现在我看到了一些关于在移动平面网格时根据噪声计算法线的帖子,但似乎无法让它为我自己工作。 下面是我的曲面分割评估着色器的一个片段,它计算新顶点的位置。 (这很好用)。

// Get the position of the newly created vert and push onto sphere's surface.
tePosition = normalize(point0 + point1 + point2) * Radius;

// Get the noise val at given location. (Using fractional brownian motion)
float noiseVal = fBM(tePosition, Octaves); 

// Push out vertex by noise amount, adjust for amplitude desired.
tePosition = tePosition + normalize(tePosition) * noiseVal * Amplitude; 

tePosition 然后进入几何着色器,其中三个用于计算三角形的表面法线。 我将如何使用它来计算所述顶点的法线?

我尝试通过在距 tePosition 两个小偏移处对噪声进行重新采样来执行“邻居”方法(我将它们推回到球体上,然后将它们替换为噪声值)。然后使用这两个新位置,我获取从 tePosition 到每个位置的向量,并使用叉积获得法线。然而,这会导致许多区域呈黑色(表明法线向后),并且法线朝外的部分在球体周围似乎非常均匀(光的另一侧的照明)。 这是执行上述操作的代码:

// theta used for small offset
float theta = 0.000001; 
// Calculate two new position on the sphere.
vec3 tangent = tePosition + vec3(theta, 0.0, 0.0);
tangent = normalize(tangent) * Radius;
vec3 bitangent = tePosition + vec3(0.0, theta, 0.0);
bitangent = normalize(bitangent) * Radius; 

// Displace new positions by noise, then calculate vector from tePosition
float tanNoise = fBM(tangent, Octaves) * Amplitude;
tangent += normalize(tangent) * tanNoise;
tangent = tangent - tePosition;

float bitanNoise = fBM(bitangent, Octaves) * Amplitude;
bitangent += normalize(bitangent) * bitanNoise;
bitangent = bitangent - tePosition;

vec3 norm = normalize(cross(normalize(tangent), normalize(bitangent)));

我尝试过改变 theta 值并更改其用于偏移的方式,这会导致不同程度的“错误”。

有人知道如何正确计算法线吗?

最佳答案

您添加的用于构造切线的向量 (theta, 0.0, 0.0)(0.0, theta, 0.0) 与球体不相切。要获得切线和双切线,您应该使用叉积:

// pos x (1,0,0) could be 0, so add pos x (0,1,0).
vec3 vecTangent = normalize(cross(tePosition, vec3(1.0, 0.0, 0.0))
  + cross(tePosition, vec3(0.0, 1.0, 0.0)));
// vecTangent is orthonormal to tePosition, compute bitangent
// (rotate tangent 90° around tePosition)
vec3 vecBitangent = normalize(cross(vecTangent, tePosition));

vec3 ptTangentSample = noisy(tePosition + theta * normalize(vecTangent));
vec3 ptBitangentSample = noisy(tePosition + theta * normalize(vecBitangent));

vec3 vecNorm = normalize(
  cross(ptTangentSample - tePosition, ptBitangentSample - tePosition));

作为旁注,我建议不要对向量(方向+长度,数学上(x,y,z,0))和点(坐标系中的位置,数学上(x,y,z)使用相同的变量,1)).

关于opengl - 从 3D 噪声计算每顶点法线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16750515/

相关文章:

c++ - 从顶点到片段着色器的平滑64位输入- “error C7570: 64 bit input should be flat”

matlab - 4 种不同的 Matlab 函数来估计数据的 PDF 给出 4 种不同的结果

css - 我们如何向线性渐变背景添加噪声?

java - 我需要在 2D Java 模拟游戏中使用 OpenGL 吗?

java - 捕获/导出 JOGL 动画到视频文件

c++ - 如何将欧拉角转换为前、上、右 vector

opengl - 您能判断是否在顶点着色器中启用了顶点属性吗?

c++ - OpenGL 实例渲染比 glBegin/glEnd 慢

opengl - 聚光灯阴影贴图的计算偏差

c++ - 清除边缘检测算法中的噪声