在OpenGL中绘制Steiner的Roman Surface

时间:2011-10-14 16:19:01

标签: c++ opengl

我正在尝试在OpenGL中绘制Steiner的罗马曲面,而我在获得正确的法线方面遇到了一些麻烦,因此表面会正常亮起。我使用维基百科的参数方程:http://en.wikipedia.org/wiki/Roman_surface。对于法线,我对theta进行了部分区分,然后是phi,然后越过偏微分来获得正常。

由于罗马表面是不可定向的表面,因此不允许表面正确点亮。因此,我想知道是否有办法让正常的法线出来,以便表面可以正确点亮。我已经尝试否定法线,整个表面和表面的一部分(否定n的第一个和最后一个四分之一),但它似乎不起作用。

我目前的代码如下:

double getRad(double deg, double n){
    return deg * M_PI / n;
}

int n = 24;

for(int i = 0; i < n; i++){
    for(int j = 0; j < 2*n; j++){

            glBegin(GL_POLYGON);

                double x = -pow(r,4) * cos(2*getRad(i+0.5,n)) * pow(cos(getRad(j+0.5,n)),2) * cos(2*getRad(j+0.5,n)) * sin(getRad(i+0.5,n)) - 2 * pow(r,4) * pow(cos(getRad(i+0.5,n)),2) * pow(cos(getRad(j+0.5,n)),2) * sin(getRad(i+0.5,n)) * pow(sin(getRad(j+0.5,n)),2);
                double y = pow(r,4) * cos(getRad(i+0.5,n)) * cos(2*getRad(i+0.5,n)) * pow(cos(getRad(j+0.5,n)),2) * cos(2*getRad(j+0.5,n)) - 2 * pow(r,4) * cos(getRad(i+0.5,n)) * pow(cos(getRad(j+0.5,n)),2) * pow(sin(getRad(i+0.5,n)),2) * pow(sin(getRad(j+0.5,n)),2);
                double z = -pow(r,4) * pow(cos(getRad(i+0.5,n)),2) * cos(getRad(j+0.5,n)) * cos(2*getRad(j+0.5,n)) * sin(getRad(j+0.5,n)) - pow(r,4) * cos(getRad(j+0.5,n)) * cos(2*getRad(j+0.5,n)) * pow(sin(getRad(i+0.5,n)),2) * sin(getRad(j+0.5,n));



                glNormal3d(x, y, z);                
                glVertex3d(r*r*cos(getRad(i,n))*cos(getRad(j,n))*sin(getRad(j,n)),r*r*sin(getRad(i,n))*cos(getRad(j,n))*sin(getRad(j,n)),r*r*cos(getRad(i,n))*sin(getRad(i,n))*cos(getRad(j,n))*cos(getRad(j,n)));
                glVertex3d(r*r*cos(getRad(i+1,n))*cos(getRad(j,n))*sin(getRad(j,n)),r*r*sin(getRad(i+1,n))*cos(getRad(j,n))*sin(getRad(j,n)),r*r*cos(getRad(i+1,n))*sin(getRad(i+1,n))*cos(getRad(j,n))*cos(getRad(j,n)));
                glVertex3d(r*r*cos(getRad(i+1,n))*cos(getRad(j+1,n))*sin(getRad(j+1,n)),r*r*sin(getRad(i+1,n))*cos(getRad(j+1,n))*sin(getRad(j+1,n)),r*r*cos(getRad(i+1,n))*sin(getRad(i+1,n))*cos(getRad(j+1,n))*cos(getRad(j+1,n)));
                glVertex3d(r*r*cos(getRad(i,n))*cos(getRad(j+1,n))*sin(getRad(j+1,n)),r*r*sin(getRad(i,n))*cos(getRad(j+1,n))*sin(getRad(j+1,n)),r*r*cos(getRad(i,n))*sin(getRad(i,n))*cos(getRad(j+1,n))*cos(getRad(j+1,n)));
            glEnd();

            glFlush();

    }
}

3 个答案:

答案 0 :(得分:2)

如果您正在处理不可移动的表面(如Steiner's Romans或着名的Möbius条带),您必须具备以下功能:启用双面照明

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

或者启用面部剔除并使用两次传递(正面和背面)渲染曲面 - 您必须否定背面传递的法线。

glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); // backside faces are NOT rendered
draw_with_positive_normals();
glCullFace(GL_FRONT);
draw_with_negative_normals();

答案 1 :(得分:0)

对于您生成的每个三角形,创建一个具有相同坐标/法线的三角形,但以另一种方式缠绕/翻转。

答案 2 :(得分:0)

通过将多边形分成两个三角形,您可能会得到更好的结果 - 每个三角形都可以保证是平面的。此外,您可以从每个三角形生成法线,或者在相邻三角形之间平滑它们。

另一个技巧是将您的点预先生成一个数组,然后在glVertex调用中引用该数组。这样你就可以有更多关于如何生成法线的选项。

此外,您可以使用glBegin(GL_LINES)... glEnd()序列渲染法线。