【问题标题】:How to generate normals in GLSL如何在 GLSL 中生成法线
【发布时间】:2015-10-31 01:55:18
【问题描述】:

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

      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,否则它看起来像一群有色人种。在我真正知道我在看什么之前,我无法继续在地形上取得进展,但我知道如何使用法线的唯一方法是将它们与模型一起加载并将它们发送到着色器。我不知道如何实际生成它们。我已经四处搜索并阅读了很多关于获取周围面的法线并将它们归一化以及其他一些内容,但我不了解其中的大部分内容,据我所知,您只能访问顶点中的单个顶点一次着色器,所以我不确定您将如何处理整个三角形。如您所见,我们将不胜感激。

编辑:

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

      float [ ] triNormals = new float [ indices.length ];

      for ( int i = 0 , index = 0 ; i < indices.length ;  )
      {
         float x , y , z;

         x = vertices [ ( 3 * indices [ i ] ) ];
         y = vertices [ ( 3 * indices [ i ] ) + 1 ];
         z = vertices [ ( 3 * indices [ i ++ ] ) + 2 ];

         Vector3f p1 = new Vector3f ( x , y , z );

         x = vertices [ ( 3 * indices [ i ] ) ];
         y = vertices [ ( 3 * indices [ i ] ) + 1 ];
         z = vertices [ ( 3 * indices [ i ++ ] ) + 2 ];

         Vector3f p2 = new Vector3f ( x , y , z );

         x = vertices [ ( 3 * indices [ i ] ) ];
         y = vertices [ ( 3 * indices [ i ] ) + 1 ];
         z = vertices [ ( 3 * indices [ i ++ ] ) + 2 ];

         Vector3f p3 = new Vector3f ( x , y , z );

         Vector3f u = Vector3f.subtract ( p2 , p1 );
         Vector3f v = Vector3f.subtract ( p3 , p1 );

         Vector3f normal = Vector3f.crossProduct ( u , v );

         triNormals [ index ++ ] = normal.x;
         triNormals [ index ++ ] = normal.y;
         triNormals [ index ++ ] = normal.z;
      }

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

【问题讨论】:

    标签: java android opengl-es glsl normals


    【解决方案1】:

    通过标准化两条边的叉积来生成每个三角形或面法线,这些法线看起来平坦且边缘锋利。正如@neuo 所说,这可以在几何着色器中完成,但听起来你在追求“平滑”的法线。

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

    在 GL 中,每个顶点都有一个法线*。所以从一个新的零数组开始,它等于你的顶点(或者如果你交错,顶点之间有空间)。对于由索引数组 (a, b, c) 形成的每个三角形,使用叉积 (b - a) × (c - a) 找到三角形法线并将其归一化。然后将三角形法线添加到每个三角形顶点的每个顶点法线(即a,b和c)。最后运行每个正常​​并正常化。完成。

    根据网格,这个简单的方法可以很好地工作。在三角形非常小或非常细的情况下,相等的权重会导致奇怪的结果:

    解决此问题的一种方法是将每个三角形的法线贡献按其面积进行缩放。为此,只需在将叉积结果添加到每个法线之前不要对其进行归一化。

    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

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

    【讨论】:

    • 我不认为几何着色器已经实现到 opengl es 中
    • @ȘēϺƤƎƦɅɱƁŖǬŚƇɄƧ 我的错。错过了 -es 位。
    • 没关系,有其他选择吗?
    • 我设法计算了三角形的法线(查看编辑)我如何使用这些来找到顶点的法线?
    • 将三角形法线添加到该三角形的顶点法线。然后遍历每个顶点法线并进行归一化。仔细看看我的代码和你的不同。特别是“每个顶点都有一个法线。所以从一个新的零数组开始,等于你的顶点”,不等于索引的数量。
    【解决方案2】:

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

    或者,提前用 CPU 计算法线,并在着色器中对法线应用必要的变换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-08
      • 2013-08-14
      • 2023-03-06
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多