OpenGL计算法线(四边形)

OpenGL Calculating Normals (Quads)

本文关键字:四边形 计算 算法 OpenGL      更新时间:2023-10-16

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

我在下面附加的函数接受一个交错的顶点阵列,并计算每4个顶点的法线。这些表示具有相同方向的四边形。根据我的理解,这4个顶点应该共享相同的法线。只要他们面对同样的方式。

我遇到的问题是,我的QUADS是用对角线渐变渲染的,很像这样:灯光效果-除了阴影在中间,灯光在角落。

我以一贯的方式画我的QUADS。TopLeft、TopRight、BottomRight、BotomLeft和用于计算法线的顶点分别为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];
    }
}
}

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

看起来你的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、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共享相同的索引),这不应该发生。


建议:

  1. 把一切都安排好
  2. 两者之一:
    1. 使用数学库
    2. 或者将矢量算法放入单独的、命名恰当的子程序中
  3. 使用命名变量而不是索引

通过这样做,您将减少代码中的错误数量。a.position.xquad[0][5]更容易读取,并且当代码没有被复制粘贴时,它更容易修复矢量运算中的拼写错误。


您可以使用并集通过索引和名称访问矢量分量:

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

用于计算四边形中的法线ABCD

A--B
|  |
C--D

使用公式:

normal=归一化((B.位置-A.位置)X(C.位置-A.职位))。

normal=归一化((D.位置-A.位置)X(C.位置-B.位置))。

其中"X"表示"叉积"。

无论哪种方式都可以。