开发者

Drawing Steiner's Roman Surface in OpenGL

I'm trying to draw Steiner's Roman Surface in OpenGL, and I'm having some trouble getti开发者_开发知识库ng the right normals so that the surface lights up correctly. I used the parametric equation from Wikipedia : http://en.wikipedia.org/wiki/Roman_surface. For the normals, I did a partial differentiation with respect to theta, then phi, then crossed the partial differentials to get the normal.

This doesn't allow the surface to light up properly because the Roman Surface is a non-orientable surface. Hence, I was wondering if there's a way to get the right normals out so that the surface can light up correctly. I've tried negating the normals, for the whole surface, and part of the surface(negating for the 1st and last quarter of n), but it doesn't seem to work.

My current code is as follows:

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();

    }
}


In the case you're dealing with nonorientable surfaces (like Steiner's Romans, or the famous Möbius strip) you have to possiblilities: Enable double sided lighting

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

or you enable face culling and render the surface with two passes (front facing and back facing) – you'll have to negate the normals for the backface pass.

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


You would probably get better results by splitting the polygon into two triangles - each would then be guaranteed to be planar. Further, you could can generate the normals from each triangle, or smooth them between neighboring triangles.

The other trick is to pre-generate your points into an array and then referencing the array in the glVertex call. That way you have more options about how to generate normals.

Also, you can render the normals themselves with a glBegin(GL_LINES) ... glEnd() sequence.


For every triangle you generate create one with the same coordinates/normals but wound/flipped the other way.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜