OpenGL 计算法线(四边形)

Posted

技术标签:

【中文标题】OpenGL 计算法线(四边形)【英文标题】:OpenGL Calculating Normals (Quads) 【发布时间】:2012-01-17 16:21:17 【问题描述】:

我的问题是关于 OpenGL 和 Normals,我了解它们背​​后的数学原理,并且取得了一些成功。

我在下面附加的函数接受一个交错的顶点数组,并计算每 4 个顶点的法线。这些代表具有相同方向的QUADS。据我了解,这 4 个顶点应该共享相同的法线。只要他们面朝同一个方向。

我遇到的问题是我的 QUADS 使用对角渐变进行渲染,就像这样:Light Effect - 除了阴影在中间,光线在角落。

我以一致的方式绘制我的 QUADS。 TopLeft、TopRight、BottomRight、BottomLeft,我用来计算法线的顶点是 TopRight - TopLeft 和 BottomRight - TopLeft。

希望有人能看到我犯了错误的事情,但我已经做了几个小时没有成功。

为了记录,我渲染了一个立方体,并在我的对象旁边有一个茶壶来检查我的照明是否正常工作,所以我相当确定灯光位置没有问题。

void CalculateNormals(point8 toCalc[], int toCalcLength)

    GLfloat N[3], U[3], V[3];//N will be our final calculated normal, U and V will be the subjects of cross-product
    float length;

for (int i = 0; i < toCalcLength; i+=4) //Starting with every first corner QUAD vertice

    U[0] = toCalc[i+1][5] - toCalc[i][5]; U[1] = toCalc[i+1][6] - toCalc[i][6]; U[2] = toCalc[i+1][7] - toCalc[i][7]; //Calculate Ux Uy Uz 
    V[0] = toCalc[i+3][5] - toCalc[i][5]; V[1] = toCalc[i+3][6] - toCalc[i][6]; V[2] = toCalc[i+3][7] - toCalc[i][7]; //Calculate Vx Vy Vz

    N[0] = (U[1]*V[2]) - (U[2] * V[1]);
    N[1] = (U[2]*V[0]) - (U[0] * V[2]);
    N[2] = (U[0]*V[1]) - (U[1] * V[0]);

    //Calculate length for normalising
    length = (float)sqrt((pow(N[0],2)) + (pow(N[1],2)) + (pow(N[2],2)));

    for (int a = 0; a < 3; a++)
    
        N[a]/=length;
    

    for (int j = 0; i < 4; i++)
    
                    //Apply normals to QUAD vertices (3,4,5 index position of normals in interleaved array)
        toCalc[i+j][3] = N[0]; toCalc[i+j][4] = N[1]; toCalc[i+j][5] = N[2];
    


【问题讨论】:

这是 C++;您是否考虑过使用数学库,例如 GLM? 很遗憾,这是一个作业,因此我们不鼓励使用库。 【参考方案1】:

您似乎正在从索引 5、6 和 7 中获取顶点位置值以用于计算,然后在索引 3、4 和 5 处写出法线。请注意索引 5 是如何在两者上使用的。我想其中一个是不正确的。

【讨论】:

非常感谢,我有一种感觉是一些小问题让我眼前一亮。截止日期是星期四,所以我一直在不停地工作以解决最后的问题。【参考方案2】:

你的for-loops好像在咬你。

for (int i = 0; i < toCalcLength; i+=4) //Starting with every first corner QUAD vertice

  ...
  for (int j = 0; i < 4; i++)
   //            ^      ^
    // Should you be using 'j' instead of 'i' here?
    // j will never increment
    // This loop won't be called at all after the first time through the outer loop
    ...
  

【讨论】:

很好,这解决了一个大问题。谢谢!【参考方案3】:

您使用索引 3、4 和 5 来存储法线:

toCalc[i+j][3] = N[0]; toCalc[i+j][4] = N[1]; toCalc[i+j][5] = N[2];

AND 您使用索引 5、6 和 7 来获取点坐标:

U[0] = toCalc[i+1][5] - toCalc[i][5]; U[1] = toCalc[i+1][6] - toCalc[i][6]; U[2] = toCalc[i+1][7] - toCalc[i][7];

这些索引重叠(normal.x 与 position.z 共享相同的索引),这不应该发生。


建议:

    将所有内容放入结构中。 要么:
      使用数学库。 或将向量算术放入单独的适当命名的子例程中。
    使用命名变量而不是索引。

这样做可以减少代码中的错误数量。 a.position.xquad[0][5] 更容易阅读,并且在代码没有被复制粘贴的情况下更容易修复向量操作中的拼写错误。


您可以使用联合通过索引和名称访问向量组件:

struct Vector3
    union
        struct
            float x, y, z;
        ;
        float v[3];
    ;
;    

用于计算四边形 ABCD 的法线

A--B
|  |
C--D

使用公式:

normal = normalize((B.position - A.position) X (C.position - A.position))。

normal = normalize((D.position - A.position) X (C.position - B.position))。

其中“X”表示“叉积”。

无论哪种方式都可以正常工作。

【讨论】:

感谢您的输入,数学已经到位,但正如您正确指出的那样,我的法线与顶点重叠。

以上是关于OpenGL 计算法线(四边形)的主要内容,如果未能解决你的问题,请参考以下文章

计算顶点法线OpenGL

重新计算规则网格表面的法线 (C++/OpenGL)

计算与加载 OpenGL 的法线

如何在OpenGL中计算三角形网格的顶点法线?

C ++ / openGL:使用四元数将QUAD旋转到一个点

用opengl实现网格[重复]