OpenGL 计算法线(四边形)
我的问题是关于 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
看起来您正在从索引 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.
看起来你的
for 循环
正在咬你。It looks like your
for-loops
are biting you.您使用索引 3、4 和 5 来存储法线:
并且您使用索引 5、6 和 7 来获取点坐标:
这些索引重叠(normal.x 与position.z 共享相同的索引),这是不应该发生的。
建议:
通过这样做,您将减少代码中的错误数量。
a.position.x
比quad[0][5]
更容易阅读,并且在代码未经过修改时更容易修复向量运算中的拼写错误。复制粘贴。您可以使用并集按索引和名称访问向量分量:
对于计算四边形 ABCD 中的
法线使用公式:
法线 = 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:
AND you use indexes 5, 6 and 7 to get point coordinates:
Those indexes overlap (normal.x shares same index as position.z), which shouldn't be happening.
Recommendations:
By doing so you'll reduce number of bugs in your code.
a.position.x
is easier to read thanquad[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:
For calcualting normal in quad ABCD
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.