【问题标题】:Are my normals to the vertices supposed to be like this?我的顶点法线应该是这样的吗?
【发布时间】:2011-11-13 03:03:26
【问题描述】:

我正在使用四边形绘制一个球体。我绘制了一个额外的顶点,只是为了将四边形分成 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;


             }
        }
   }

【问题讨论】:

  • 是的。我很难理解它。这就是为什么我在这里发帖,为了澄清一下
  • 当然,您的讲师已经谈到了曲面法线是什么。这个家庭作业不是你第一次听说这个词。
  • 如果这一系列问题(以及明显拒绝遵循任何像样的OpenGL教程)是全班的代表,那么讲师需要被带走并枪毙:o

标签: c++ opengl


【解决方案1】:

在我看来,您的问题是,您并没有真正掌握实际发生的情况。您应该掌握数学概念,而不是查看某些教程中的代码(尝试从代码中过滤这些概念会适得其反,因为代码并不能说明完整的故事,并且可能会省略或简化一些事情以获得足够好的近似值) .

首先你得到了顶点的顺序,好吧,没有错,但是不开心。 OpenGL 在矢量计算中假定为右手习惯(除非您在转换管道的末端交换一个轴)。这意味着,顶点应该逆时针计数。你可以顺时针做,但反过来事情会容易得多。接下来,您应该从 0 开始计数,至少如果您使用类似 C 的语言,该语言通过偏移索引来寻址数组,即第一个元素位于索引 0 处。

3--2
| /|
|/ |
0--1

原点中心球体的法线是特殊的,因为规范化(不要将“正常”与 normalnormal 混淆,它们是不同的东西!)顶点位置向量是相关顶点的法线。

在一般情况下,可以通过取顶点的切空间的叉积来评估法线,即对于三角形,可以通过角处的边向量的叉积来评估。在您的四边形的情况下,[0] 处的法线将是

normalize( ([1]-[0]) × ([2]-[0]) )

对于三角形 0,1,2 和

normalize( ([2]-[0]) × ([3]-[0]) )

注意,这是表面分析表示的偏导数的叉积。您已经知道球体表面的解析表示(参见 Paul Bourke 的教程)。我建议作为一个练习来测试这一点,即证明对于以原点为单位半径的球体,表面上一个点的位置等于该点的表面法线。

【讨论】:

    【解决方案2】:

    冒着repeating myself的风险:

    对于球体上给定的向量位置 P,其中心为 C,法线为 norm(P - C),其中 norm 对向量进行归一化。

    我没有看到您的代码这样做。除非您知道这些位置以原点为中心,这不是您所说的假设。

    【讨论】:

    • C 是我的中心,它在原点上。 (0,0,0)
    • @TrtTrt:那么你的顶点位置是错误的。我们无法确定,因为您没有向我们展示您是如何计算它们的;我们只能按照您发布的内容进行。
    • 我编辑了问题并添加了顶点计算。这是我在这里找到的算法。 paulbourke.net/miscellaneous/sphere_cylinder我的计算怎么会出错?球体看起来很好。这是我没有得到的
    【解决方案3】:

    看起来你应该画的是一个由正方形组成的球体,想象一个橙色,上面画着一堆正方形。

    因为他想要顶点法线,所以每个四边形将在其每个顶点绘制四个法线,每个法线垂直于四边形表面

    请注意,每个顶点将有四个不同的顶点法线,因为每个顶点由四个四边形共享。

    edit:在光照的上下文中,他可能希望每个顶点都有一个法线,所以只取平均值。这可能是他的意思,但不是说明书上说的。

    【讨论】:

    • 所以顶点与它无关?我的意思是我从每个四边形绘制 4 条“线”(即每个顶点一条)​​,但现在我只需要计算 1 条线。嗯,好的,谢谢。
    • 我觉得指令一般只是不好——如果你想做光照,那么每个顶点应该只有一个法线,可以通过取四个共享的四边形的法线的平均值来找到正常的。还有其他方法可以做到这一点,但平均它们是最简单的
    • 好的,非常感谢您的回答,我开始澄清我的想法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多