OpenGL - Rotate a 'Curve' About the Y-Axis

前端 未结 3 1594
隐瞒了意图╮
隐瞒了意图╮ 2020-12-19 18:03

As per my question on Math Stackexchange:

I am working on a project for my 3D Graphics class. The project is built with C++ and OpenGL / Glut. Basically, I

相关标签:
3条回答
  • 2020-12-19 18:10

    Looks like you're trying to construct a surface of revolution/solid of revolution/"lathe object".

    A working example:


    #include <GL/glut.h>
    #include <glm/glm.hpp>
    #include <vector>
    #include <cmath>
    
    using namespace std;
    using namespace glm;
    
    struct Vertex
    {
        Vertex( const vec3& position, const vec3& normal )
            : position( position )
            , normal( normal ) 
        {}
        vec3 position;
        vec3 normal;
    };
    
    // spin the pts array around the Z axis.
    // pts.x will become the radius, and pts.y will become the height
    // pts should be sorted by y-coordinate
    vector< Vertex > Lathe( const vector< vec2 >& pts, unsigned int segments = 32 )
    {
        // precalculate circle points
        vector< vec2 > circlePts;
        for( unsigned int i = 0; i <= segments; ++i )
        {
            float angle = ( i / (float)segments ) * 3.14159f * 2.0f;
            circlePts.push_back( vec2( cos( angle ), sin( angle ) ) );
        }
    
        // fill each layer
        typedef vector< vec3 > Layer;
        typedef vector< Layer > Layers;
        Layers layers( pts.size(), Layer( circlePts.size() ) );
        for( size_t i = 0; i < pts.size(); ++i )
        {
            for( unsigned int j = 0; j < circlePts.size(); ++j )
            {
                layers[i][j] = vec3( circlePts[j] * pts[i].x, pts[i].y );
            }
        }
    
        // move through layers generating triangles
        vector< Vertex > verts;
        for( size_t i = 1; i < layers.size(); ++i )
        {
            const Layer& prvLayer = layers[ i-1 ];
            const Layer& curLayer = layers[ i-0 ];
            for( size_t j = 1; j < circlePts.size(); ++j )
            {
                //    upper = cur layer
                //        UL -- UR  
                // left   | 0 /  |  right 
                // = j-1  |  / 1 |  = j-0
                //        LL -- LR  
                //    lower = prv layer
                const vec3& LL = prvLayer[ j-1 ]; // lower-left
                const vec3& LR = prvLayer[ j-0 ]; // lower-right
                const vec3& UL = curLayer[ j-1 ]; // upper-left
                const vec3& UR = curLayer[ j-0 ]; // upper-right
    
                // triangle0: LL -> UR -> UL
                const vec3 normal0 = normalize( cross( UR - LL, UL - LL ) );
                verts.push_back( Vertex( LL, normal0 ) );
                verts.push_back( Vertex( UR, normal0 ) );
                verts.push_back( Vertex( UL, normal0 ) );
    
                // triangle1: LL -> LR -> UR
                const vec3 normal1 = normalize( cross( LR - LL, UL - LL ) );
                verts.push_back( Vertex( LL, normal1 ) );
                verts.push_back( Vertex( LR, normal1 ) );
                verts.push_back( Vertex( UR, normal1 ) );
            }
        }
    
        return verts;
    }
    
    // mouse state
    int btn;
    ivec2 startMouse;
    ivec2 startRot, curRot;
    
    void mouse(int button, int state, int x, int y )
    {
        if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
        {
            btn = button;
            startMouse = ivec2( x, glutGet( GLUT_WINDOW_HEIGHT ) - y );
            startRot = curRot;
        }
    }
    
    void motion( int x, int y )
    {
        ivec2 curMouse( x, glutGet( GLUT_WINDOW_HEIGHT ) - y );
        if( btn == GLUT_LEFT_BUTTON )
        {
            curRot = startRot + ( curMouse - startMouse );
        }
        glutPostRedisplay();
    }
    
    vector< Vertex > model;
    void display()
    {
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        double w = glutGet( GLUT_WINDOW_WIDTH );
        double h = glutGet( GLUT_WINDOW_HEIGHT );
        double ar = w / h;
        gluPerspective( 60, ar, 0.1, 40 );
    
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        glTranslatef( 0, 0, -10 );
    
        glPushMatrix();
        glRotatef( curRot.x % 360, 0, 1, 0 );
        glRotatef( -curRot.y % 360, 1, 0, 0 );
    
        // draw model
        if( !model.empty() )
        {
            glColor3ub( 255, 0, 0 );
            glEnableClientState( GL_VERTEX_ARRAY );
            glEnableClientState( GL_NORMAL_ARRAY );
            glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), &model[0].position );
            glNormalPointer( GL_FLOAT, sizeof(Vertex), &model[0].normal );
            glDrawArrays( GL_TRIANGLES, 0, model.size() );
            glDisableClientState( GL_VERTEX_ARRAY );
            glDisableClientState( GL_NORMAL_ARRAY );
        }
    
        // draw bounding cube
        glDisable( GL_LIGHTING );
        glColor3ub( 255, 255, 255 );
        glutWireCube( 7 );
        glEnable( GL_LIGHTING );
    
        glPopMatrix();
    
        glutSwapBuffers();
    }
    
    int main( int argc, char **argv )
    {
        vector< vec2 > pts;
        pts.push_back( vec2( 0.1, -3 ) );
        pts.push_back( vec2( 2, -2 ) );
        pts.push_back( vec2( 3, -1 ) );
        pts.push_back( vec2( 1, 0 ) );
        pts.push_back( vec2( 3, 1 ) );
        pts.push_back( vec2( 4, 2 ) );
        pts.push_back( vec2( 4, 3 ) );
        model = Lathe( pts );
    
        glutInit( &argc, argv );
        glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
        glutInitWindowSize( 640, 480 );
        glutCreateWindow( "GLUT" );
        glutDisplayFunc( display );
        glutMouseFunc( mouse );
        glutMotionFunc( motion );
    
        glEnable( GL_DEPTH_TEST );
    
        // set up lighting
        glShadeModel( GL_SMOOTH );
        glEnable( GL_COLOR_MATERIAL );
        glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
        glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
        glEnable( GL_LIGHTING );
    
        // set up "headlamp"-like light
        glEnable( GL_LIGHT0 );
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        GLfloat position[] = { 0, 0, 1, 0 };
        glLightfv( GL_LIGHT0, GL_POSITION, position );
    
        glPolygonMode( GL_FRONT, GL_FILL );
        glPolygonMode( GL_BACK, GL_LINE );
    
        glutMainLoop();
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-19 18:25

    Edit 2: Okay, I see the problem you're running into -- it's a limitation I'd forgotten about (so the code I'd posted previously was dead wrong and wouldn't work at all). The problem is that you're not allowed to call glRotate between a glBegin/glEnd pair -- if you do, it'll set an error flag, and no more drawing will be done.

    That does mean you pretty much have to handle the rotation yourself. Fortunately, that's a bit simpler than you've tried to make it:

    static const double pi = 3.1416;
    
    for (int point=0; point<NUM_POINTS; point++) {
        glBegin(GL_LINE_STRIP);
        for (double theta = 0.0; theta < 2.0 * pi; theta += pi/6.0) {
            double x = cos(theta);
            double z = sin(theta);
            glVertex3d(points[point][0]*x, points[point][1], -1.0-points[point][0]*z);
        }
        glEnd();
    }   
    

    As-is, this code uses -1.0 along the Z axis as the center of rotation. You can obviously move that where you wish, though anything outside your clipping frustum obviously won't display.

    Also note that to get a wireframe, you'll have to draw both your "vertical", and your "horizontal" lines separately, so the code will look something like this:

    for (int point=0; point<NUM_POINTS; point++) {
        glBegin(GL_LINE_STRIP);
        for (double theta = 0.0; theta < 2.0 * pi; theta += pi/6.0) {
            double x = cos(theta);
            double z = sin(theta);
            glVertex3d(points[point][0]*x, points[point][1], -1.0 - points[point][0]*z);
        }
        glEnd();
    }
    
    for (double theta = 0.0; theta < 2.0 * pi; theta += pi/6.0) {
        glBegin(GL_LINE_STRIP);
        for (int point=0; point<NUM_POINTS; point++) {
            double x = cos(theta);
            double z = sin(theta);
            glVertex3d(points[point][0]*x, points[point][1], -1.0 - points[point][0]*z);
        }
        glEnd();
    }
    
    0 讨论(0)
  • 2020-12-19 18:31

    The trig functions take angles in radians, not degrees.

    I also suspect that your viewport isn't setup properly, which explains why you can't see anything on the screen. Typically when I think stuff isn't rendering, it usually is, however, I haven't configured the camera, lighting and other stuff correctly.

    0 讨论(0)
提交回复
热议问题