OpenGL 计算法线(四边形)

发布于 2024-12-27 14:56:26 字数 1670 浏览 1 评论 0原文

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

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

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

我以一致的方式绘制我的四边形。 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];
    }
}
}

My issue is regarding OpenGL, and Normals, I understand the math behind them, and I am having some success.

The function I've attached below accepts an interleaved Vertex Array, and calculates the normals for every 4 vertices. These represent QUADS that having the same directions. By my understanding these 4 vertices should share the same Normal. So long as they face the same way.

The problem I am having is that my QUADS are rendering with a diagonal gradient, much like this: Light Effect - Except that the shadow is in the middle, with the light in the corners.

I draw my QUADS in a consistent fashion. TopLeft, TopRight, BottomRight, BottomLeft, and the vertices I use to calculate my normals are TopRight - TopLeft, and BottomRight - TopLeft.

Hopefully someone can see something I've made a blunder on, but I have been at this for hours to no prevail.

For the record I render a Cube, and a Teapot next to my objects to check my lighting is functioning, so I'm fairly sure there is no issue regarding Light position.

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];
    }
}
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

演多会厌 2025-01-03 14:56:26

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

It seems like you are taking the vertex position values for use in calculations from indices 5, 6, and 7, and then writing out the normals at indices 3, 4, and 5. Note how index 5 is used on both. I suppose one of them is not correct.

鹿港巷口少年归 2025-01-03 14:56:26

看起来你的 for 循环 正在咬你。

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
    ...
  }
}

It looks like your for-loops are biting you.

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
    ...
  }
}
别低头,皇冠会掉 2025-01-03 14:56:26

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

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

并且您使用索引 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

法线使用公式:

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

OR

正常 = 标准化((D.位置 - A.位置) X (C.位置 - B.位置))。

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

无论哪种方式都会很好地工作。

You use indexes 3, 4, and 5 for storing normal:

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

AND you use indexes 5, 6 and 7 to get point coordinates:

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];

Those indexes overlap (normal.x shares same index as position.z), which shouldn't be happening.


Recommendations:

  1. Put everything into structures.
  2. Either:
    1. Use math library.
    2. OR put vector arithmetics into separate appropriately named subroutines.
  3. Use named variables instead of indexes.

By doing so you'll reduce number of bugs in your code. a.position.x is easier to read than quad[0][5], and it is easier to fix a typo in vector operation when the code hasn't been copy-pasted.


You can use unions to access vector components by both index and name:

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

For calcualting normal in quad ABCD

A--B
|  |
C--D

Use formula:

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

OR

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

Where "X" means "cross-product".

Either way will work fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文