如何在GLSL中生成法线

时间:2015-10-31 01:55:19

标签: java android opengl-es glsl normals

我使用单纯噪声创建了随机生成的地形。我的代码如下所示:

getDefaultSharedPreferences()

这给了我索引和顶点但是除非我使用 float [ ] vertices = new float [ SIZE * SIZE * 3 ]; short [ ] indices = new short [ ( SIZE - 1 ) * ( SIZE - 1 ) * 2 * 3 ]; for ( int x = 0 , index = 0 ; x < SIZE ; x ++ ) { for ( int z = 0 ; z < SIZE ; z ++ ) { vertices [ index ++ ] = x; vertices [ index ++ ] = ( float ) SimplexNoise.noise ( x , z ); vertices [ index ++ ] = z; } } for ( int i = 0 , index = 0 ; i < ( SIZE - 1 ) ; i ++ ) { int offset = i * SIZE; for ( int j = 0 ; j < ( SIZE - 1 ) ; j ++ ) { indices [ index ++ ] = ( short ) ( j + offset ); indices [ index ++ ] = ( short ) ( j + offset + 1 ); indices [ index ++ ] = ( short ) ( j + offset + 1 + SIZE ); indices [ index ++ ] = ( short ) ( j + offset + 1 + SIZE ); indices [ index ++ ] = ( short ) ( j + offset + SIZE ); indices [ index ++ ] = ( short ) ( j + offset ); } } 它看起来像一团颜色。在我真正了解我正在查看的内容之前,我无法继续在地形上取得进展,但我知道如何使用法线的唯一方法是使用模型加载它们并将它们发送到着色器。我不知道如何实际生成它们。我已经四处搜索并阅读了很多关于获取周围面部的法线并将它们归一化以及其他一些东西,但我对它的大部分内容并不了解,据我所知,您只能访问顶点中的单个顶点一次使用着色器,所以我不确定如何处理整个三角形。正如你所看到的,将会有很多帮助。

编辑:

我做了一些研究,现在已经计算了所有三角形的法线:

GL_LINES

现在我只需要知道如何使用周围三角形的法线来计算顶点的法线。

2 个答案:

答案 0 :(得分:0)

您可以使用Geometry Shader处理多个顶点,并计算法线。

或者,使用CPU预先计算正常,并在着色器中对法线应用必要的变换。

答案 1 :(得分:0)

通过对两条边的叉积进行归一化,生成看起来平坦且边缘锐利的每三角形或面法线。正如@neuo所说,这可以在几何着色器中完成,但听起来就像你在“平滑”法线之后。

enter image description here

平滑法线不一定隐含在顶点几何体中,但是一个不错的猜测是基于相邻三角形(平均值或加权平均值)。除非您有邻接信息(如曲面细分着色器(?)),否则在渲染时无法在GLSL中进行。它需要在单独的传递中完成(可能使用转换反馈),并且可能在CPU上处理起来很容易。

在GL中,每个顶点都有一个法线*。因此,从一个新的归零数组开始,该数组等于您的顶点(如果交错,则使用顶点之间的空格)。对于由索引数组(a,b,c)形成的每个三角形,使用叉积(b - a)×(c - a)找到三角形法线并对其进行标准化。然后将三角形法线加到每个三角形顶点的每个顶点法线(即a,b和c)。最后贯穿每一个正常和规范化。完成。

根据网格,这种简单的方法可以很好地工作。如果三角形真的很小或很瘦,那么相等的加权会导致奇怪的结果:

enter image description here enter image description here

解决此问题的一种方法是按比例缩放每个三角形的正常贡献。要执行此操作,只需在将交叉产品结果添加到每个法线之前不对其进行标准化。

for (int t = 0; t < numIndices / 3; ++t)
{
    unsigned int t1 = dataIndices[t*3+0];
    unsigned int t2 = dataIndices[t*3+1];
    unsigned int t3 = dataIndices[t*3+2];
    const vec3f& a = verts[t1];
    const vec3f& b = verts[t2];
    const vec3f& c = verts[t3];
    vec3f u = b - a;
    vec3f v = c - a;
    vec3f n = u.cross(v);
    //if (n.size() > 0.0) n.normalize(); //removes weighting based on triangle area
    norms[t1] += n;
    norms[t2] += n;
    norms[t3] += n;
}
for (int v = 0; v < numVertices; ++v)
    norms[v].normalize();

src

*要获得面法线,您必须复制顶点,这就是为每个顶点位置绘制两个红色法线的图像的原因。您也可以在flat变量上使用关键字in/out,但一切都会变平。