OpenGL Glut C - want to render curved cylinder

十年热恋 提交于 2021-02-16 16:31:31

问题


The following code shows a straight cylinder/pipe in OpenGL C language.

 #include <stdio.h>
 #include <stdlib.h>
 #include <GL/glut.h>
 #include <math.h>
 #define PI 3.1415927

void draw_cylinder(GLfloat radius, GLfloat height, GLubyte R, GLubyte G, GLubyte B)
{
    GLfloat x = 0.0;
    GLfloat y = 0.0;
    GLfloat angle = 0.0;
    GLfloat angle_stepsize = 0.1;

    // Draw the tube
    glColor3ub(R-40,G-40,B-40);
    glBegin(GL_QUAD_STRIP);
        angle = 0.0;
        while( angle < 2*PI ) {
            x = radius * cos(angle);
            y = radius * sin(angle);
            glVertex3f(x, y , height);
            glVertex3f(x, y , 0.0);
            angle = angle + angle_stepsize;
        }
        glVertex3f(radius, 0.0, height);
        glVertex3f(radius, 0.0, 0.0);
    glEnd();

    // Draw the circle on top of cylinder
    glColor3ub(R,G,B);
    glBegin(GL_POLYGON);
        angle = 0.0;
        while( angle < 2*PI ) {
            x = radius * cos(angle);
            y = radius * sin(angle);
            glVertex3f(x, y , height);
            angle = angle + angle_stepsize;
        }
        glVertex3f(radius, 0.0, height);
    glEnd();
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();

    glTranslatef(-0.5,0.0,-2.5);
    glRotatef(100.0, 0.725, 1.0, 1.0);

    draw_cylinder(0.15, 1.0, 255, 160, 100);

    glFlush();
}

void reshape(int width, int height)
{    
    if (width == 0 || height == 0) return;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(35.0, (GLdouble)width/(GLdouble)height,0.5, 20.0);

    glMatrixMode(GL_MODELVIEW);
    glViewport(0, 0, width, height);
}    

int main(int argc, char **argv)
{    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(640,580);
    glutCreateWindow("Create Cylinder");
    glClearColor(0.0,0.0,0.0,0.0);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);

    glutMainLoop();

    return 0;
}

At the moment it draws a straight cylinder/pipe. And I wanted to curve it to look like this.


回答1:


First I recommend to split the cylinder into slices. The following cone will draw exactly the same cylinder, but it splits the cylinder int slices. The slices have different colors to visualize the effect.

GLfloat h0, h1, angle, x, y;
int i, j;

int     slices      = 8;

for ( i = 0; i < slices; i++ )
{
    h0 = (float)i / (float)slices;
    h1 = (float)(i+1) / (float)slices;

    glColor3f( 1.0f-h0, 0.0, h1 );
    glBegin(GL_QUAD_STRIP);
        for ( j = 0; j <= 360; ++ j )
        {
            angle = PI * (float)j * PI / 180.0f;
            x = radius * cos(angle);
            y = radius * sin(angle);
            glVertex3f( x, y, h0 );
            glVertex3f( x, y, h1 );
        }
    glEnd();
}

Then you have to define a bend radius and a bend start and end angle. The following code draw a bended pipe form bend_ang0 to bend_ang1, with a radius bend_radius. The bend angles can be calculated in relation to the bend radius and the length of the pipe:

GLfloat w0, w1, ang0, ang1, angle, x, y, xb, yb, zb;
int i, j;

int     slices      = 8;
GLfloat bend_radius = 1.0f;

GLfloat bend_angle, bend_ang0, bend_ang1; 

bend_angle = bend_radius * height;
bend_ang0  = -bend_angle/2.0f;
bend_ang1  = bend_angle/2.0f;

for ( i = 0; i < slices; i++ )
{
    w0 = (float)i / (float)slices;
    w1 = (float)(i+1) / (float)slices;

    ang0 = bend_ang0 + (bend_ang1-bend_ang0) * w0;
    ang1 = bend_ang0 + (bend_ang1-bend_ang0) * w1;

    glColor3f( 1.0f-w0, 0.0, w1 );
    glBegin(GL_QUAD_STRIP);

        for ( j = 0; j <= 360; ++ j )
        {
            angle = PI * (float)j * PI / 180.0f;
            x = radius * cos(angle) + bend_radius;
            y = radius * sin(angle);

            xb = sin( ang0 ) * x;
            yb = y;
            zb = cos( ang0 ) * x;
            glVertex3f( xb, yb, zb );

            xb = sin( ang1 ) * x;
            yb = y;
            zb = cos( ang1 ) * x;
            glVertex3f( xb, yb, zb );
        }
    glEnd();
}

For the following image I activated the depth test and changed the model view matrix:

void display(void)
{
    glEnable( GL_DEPTH_TEST );
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glTranslatef(0.0f, -0.5f, -4.0f);
    glRotatef(-90.0f, 1.0f, 0.0, 0.0f);

    draw_cylinder(0.15, 2.0, 255, 160, 100);

    glFlush();
}




回答2:


Currently you are drawing the entire height of the cylinder in one go ... to create a curved surface you must instead take your existing code and have it create a succession of tiny cylinders each with a tiny height then stack them up to consume the original height.

One approach would be to introduce a new function which becomes the parent of your

void draw_cylinder(GLfloat radius, GLfloat height, GLubyte R, GLubyte G, GLubyte B)

perhaps call it

draw_curved_cylinder

inside this new function you have a loop where you make calls to draw_cylinder giving it the parameters of each of these tiny cylinders ... currently your draw function blindly stretches the height from 0 to your given height ... replace that with settings for the given tiny cylinder ... also to make the final cylinder curved each tiny cylinder must have its X and Y coordinates follow the curved trajectory so in that new function draw_curved_cylinder increment those so they vary as your synthesize each new tiny cylinder

PS - be aware that you are not using modern OpenGL - glBegin is obsolete and should be avoided



来源:https://stackoverflow.com/questions/52930454/opengl-glut-c-want-to-render-curved-cylinder

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!