我的顶点法线应该是这样的吗?
我正在使用四边形绘制一个球体。我绘制了一个额外的顶点,只是为了将四边形分成 2 个三角形。所以它是这样的:
1 ----> 2
| |
| |
4 ----> 3
但在 3 之后我再次绘制 1。因此,想象一下从 3-->1 开始的额外一行。
我现在正在尝试计算每个顶点的法线。 这是我的代码:
//calculate normals
for (no_vertice=0; no_vertice<12887; no_vertice+=1)
{
//getting the sphere's vertices
x=sphere_vertices[no_vertice].position[0];
y=sphere_vertices[no_vertice].position[1];
z=sphere_vertices[no_vertice].position[2];
//normalising vector "norm(Vertex - Center)"
magnitude = sqrt((x*x) + (y*y) + (z*z));
sphere_vertices[no_vertice].normal[0] = (x/magnitude);
sphere_vertices[no_vertice].normal[1] = (y/magnitude);
sphere_vertices[no_vertice].normal[2] = (z/magnitude);
printf("Normal at vertice %d = X:%f, Y:%f, Z:%f. \n", no_vertice, sphere_vertices[no_vertice].normal[0], sphere_vertices[no_vertice].normal[1], sphere_vertices[no_vertice].normal[2]);
}
我正在计算每个顶点的大小,然后将该顶点的每个分量除以该大小,以便得到一个单位向量。问题是我得到了很多零向量。即 x=0、y=0、z=0 的顶点... 当我将法线传递给顶点着色器
//my vertex structure
struct Vertex {
GLdouble position[3];
GLfloat color[3];
GLdouble normal[3];
};
....
..
.
/* Enable attribute index 2 as being used */
glEnableVertexAttribArray ( 2 );
glVertexAttribPointer ( ( GLuint ) 2, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* )
offsetof(struct Vertex, normal) );
...
..
.
//pass the normal to vertex shader
glBindAttribLocation(shaderprogram, 2, "in_Normal");
并进行光照计算时,我得到了所有奇怪的效果。
我做错了什么吗?
最令人困惑的部分是我被要求这样做:
“对于球体,计算出表面法线方向并增强线框 用短线表示每个顶点的法线方向绘制球体 现在应该看起来像一个刺猬。”
“注意:表面法线是与表面补丁成直角的单位向量,假设它是平坦的。”
所以它基本上是顶点的法线,或者是四边形表面的法线我必须画画吗? 我很困惑,因为它说,
“计算出表面法线方向”
,然后
“用代表每个顶点法线方向的短线绘制”
那么应该在哪里绘制线???在顶点?或者在四边形的中间?谢谢
编辑:顶点计算
for (theta=-90;theta<=90-dtheta;theta+=dtheta) {
for (phi=0;phi<=360-dphi;phi+=dphi) {
//calculating Vertex 1
x = cos(theta*DTOR) * cos(phi*DTOR);
y = cos(theta*DTOR) * sin(phi*DTOR);
z = sin(theta*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
//calculating Vertex 2
x = cos((theta+dtheta)*DTOR) * cos(phi*DTOR);
y = cos((theta+dtheta)*DTOR) * sin(phi*DTOR);
z = sin((theta+dtheta)*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
//calculating Vertex 3
x = cos((theta+dtheta)*DTOR) * cos((phi+dphi)*DTOR);
y = cos((theta+dtheta)*DTOR) * sin((phi+dphi)*DTOR);
z = sin((theta+dtheta)*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
//adding Vertex_1 again to divide the Quad into 2 triangles
//calculating Vertex 1
x = cos(theta*DTOR) * cos(phi*DTOR);
y = cos(theta*DTOR) * sin(phi*DTOR);
z = sin(theta*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
if (theta > -90 && theta < 90) {
//calculating Vertex 4
x = cos(theta*DTOR) * cos((phi+dphi)*DTOR);
y = cos(theta*DTOR) * sin((phi+dphi)*DTOR);
z = sin(theta*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
}
}
}
I am drawing a sphere using quads. I plot an extra vertex, just to divide the quad into 2 triangles. So it goes like this:
1 ----> 2
| |
| |
4 ----> 3
but after 3 I plot 1 again. So imagine an extra line from 3-->1.
I am now trying to calculate each vertex' normal.
Here is my code:
//calculate normals
for (no_vertice=0; no_vertice<12887; no_vertice+=1)
{
//getting the sphere's vertices
x=sphere_vertices[no_vertice].position[0];
y=sphere_vertices[no_vertice].position[1];
z=sphere_vertices[no_vertice].position[2];
//normalising vector "norm(Vertex - Center)"
magnitude = sqrt((x*x) + (y*y) + (z*z));
sphere_vertices[no_vertice].normal[0] = (x/magnitude);
sphere_vertices[no_vertice].normal[1] = (y/magnitude);
sphere_vertices[no_vertice].normal[2] = (z/magnitude);
printf("Normal at vertice %d = X:%f, Y:%f, Z:%f. \n", no_vertice, sphere_vertices[no_vertice].normal[0], sphere_vertices[no_vertice].normal[1], sphere_vertices[no_vertice].normal[2]);
}
I am calculating the magnitude for each vertex, and then dividing each component of that vertex with the magnitude so I get a unit vector. The problem is that I get a lot of zero vectors. that is vertices with x=0, y=0, z=0...
When I pass the normal to the vertex shader,
//my vertex structure
struct Vertex {
GLdouble position[3];
GLfloat color[3];
GLdouble normal[3];
};
....
..
.
/* Enable attribute index 2 as being used */
glEnableVertexAttribArray ( 2 );
glVertexAttribPointer ( ( GLuint ) 2, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* )
offsetof(struct Vertex, normal) );
...
..
.
//pass the normal to vertex shader
glBindAttribLocation(shaderprogram, 2, "in_Normal");
and do my light calculation I get all weird kind of effects.
Am I doing anything wrong?
The most confusing part is I am asked to do this:
"For the sphere, work out the surface normal direction and augment your wire-frame
drawing with short lines representing the normal direction of each vertex The sphere
should now appear to be a hedge hog."
"Note: The surface normal is the unit vector at right angles to the surface patch, assuming it is flat."
So is it basically the normal to a vertex, or to the quad surface that I have to draw?
I am confused because it says,
"work out the surface normal direction"
and then
"drawing with short lines representing the normal direction of each vertex"
So where the lines should be drawn??? on the vertex? or in the middle of the quad? Thanks
EDIT: Vertex Calculation
for (theta=-90;theta<=90-dtheta;theta+=dtheta) {
for (phi=0;phi<=360-dphi;phi+=dphi) {
//calculating Vertex 1
x = cos(theta*DTOR) * cos(phi*DTOR);
y = cos(theta*DTOR) * sin(phi*DTOR);
z = sin(theta*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
//calculating Vertex 2
x = cos((theta+dtheta)*DTOR) * cos(phi*DTOR);
y = cos((theta+dtheta)*DTOR) * sin(phi*DTOR);
z = sin((theta+dtheta)*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
//calculating Vertex 3
x = cos((theta+dtheta)*DTOR) * cos((phi+dphi)*DTOR);
y = cos((theta+dtheta)*DTOR) * sin((phi+dphi)*DTOR);
z = sin((theta+dtheta)*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
//adding Vertex_1 again to divide the Quad into 2 triangles
//calculating Vertex 1
x = cos(theta*DTOR) * cos(phi*DTOR);
y = cos(theta*DTOR) * sin(phi*DTOR);
z = sin(theta*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
if (theta > -90 && theta < 90) {
//calculating Vertex 4
x = cos(theta*DTOR) * cos((phi+dphi)*DTOR);
y = cos(theta*DTOR) * sin((phi+dphi)*DTOR);
z = sin(theta*DTOR);
no_vertice+=1;
sphere_vertices[no_vertice].position[0] = x;
sphere_vertices[no_vertice].position[1] = y;
sphere_vertices[no_vertice].position[2] = z;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在我看来,你的问题是,你并没有真正掌握到底发生了什么。您应该掌握数学概念,而不是查看某些教程中的代码(尝试从代码中过滤这些概念会适得其反,因为代码不能讲述完整的故事,并且还可能省略或简化一些内容以获得足够好的近似值) 。
首先,你得到了顶点的顺序,好吧,没有错,但不高兴。 OpenGL 在矢量计算中假定右手惯用(除非您在变换管道末端交换一个轴)。这意味着,顶点应该逆时针计数。你可以顺时针方向做,但反过来事情会变得容易得多。接下来,您应该从 0 开始计数,至少如果您使用的是通过偏移索引寻址数组的 C 语言,即第一个元素位于索引 0 处。
以原点为中心的球体的法线是特殊的,因为标准化(不不要将“法线”与法线化的法线相混淆,它们是不同的东西!)顶点位置向量是所讨论顶点的法线。
在一般情况下,可以通过取顶点的切空间的叉积来评估法线,即对于三角形,取角处的边缘向量的叉积。在您的四边形的情况下,[0] 处的法线将
适用于三角形 0,1,2,并且
注意,这是表面分析表示的偏导数的叉积。您已经知道球体表面的分析表示(请参阅 Paul Bourke 的教程)。我建议作为测试这一点的练习,即证明对于原点周围的单位半径球体,曲面上一点的位置等于该点处曲面的法线。
Your problem(s), as I see them is, that you don't really have a grip for what's actually going on. Instead of looking at code from some tutorials, you should get a grip of the mathematical concepts (trying to filter those from code is counterproductive, since code doesn't tell the full story and also may omit or simplify things for a good enough approximation).
First of all you got the order of vertices, well not wrong, but unhappy. OpenGL assumes right handedness in vector calculations (unless you swap one axis at the end of the transformation pipeline). That means, vertices should be counted counterclockwise. You can do it clockwise, but things get much easier the other way round. Next you should start counting with 0, at least if you're in a C like language that addresses arrays by offset index, i.e. first element is at index 0.
The normals of a origin centered sphere are something special, since normalized (don't confuse a "normal" with the normal of normal-ized, they're different things!) vertex position vectors are the normal of the vertex in question.
In the general case a normal can be evaluated by taking the cross product of the tangent space of the vertex, i.e. for a triangle the cross product of the edge vectors at a corner. In your quad's case the normal at [0] would be
for the triangle 0,1,2 and
Notice, that this is the cross product of the partial derivatives of the analytical representation of the surface. You already know the analytical representation of a sphere's surface (see Paul Bourke's tutorial). I recommend as an exercise to test this, i.e. proof that for a unit radius sphere around the origin, the position of a point of the surface equals the surface's normal at that point.
冒着重复自己的风险:
我没有看到你的代码这样做。除非您知道位置以原点为中心,这不是您所说的假设。
At the risk of repeating myself:
I don't see your code doing this. Unless you know that the positions are centered on the origin, which is not an assumption you have stated.
看起来你应该画的是一个由正方形组成的球体,想象一个橙色,上面画了一堆正方形。
由于他想要顶点法线,因此每个四边形将在其每个顶点处绘制四个法线,每个法线垂直于四边形表面。
请注意,每个顶点将具有四个不同的顶点法线,因为每个顶点由四个四边形共享。
编辑:在照明的背景下,他可能希望每个顶点都有一个法线,所以只需取平均值。这可能是他的意思,但不是说明书上所说的。
It looks like what you are supposed to draw is a sphere made up of squares, imagine an orange with a bunch of squares painted onto it.
Since he wants the vertex normals, each quad will have four normals drawn at each of its vertices, with each normal perpendicular to the quads surface
Note that each vertex would have four different vertex normals, since each vertex is shared by four quads.
edit: In the context of lighting, he probably wants a single normal for each vertex, so just take the average. This is probably what he means, but its not what the instructions say.