Search code examples
copengl3dopengl-compatquad

What would be the C code to draw a cylinder between 2 3D vectors in OpenGL? I want it to get proportionally bigger as it is closer to viewer


I'm trying to implement a quad function to draw lines. My goal is to be able to display a beam from one 3D spot to another. But I'm failing at it. Also I want to be able to specify a 3D thickness parameter in the function that draws the quad/cylinder. Do I need to draw a cylinder? if not, how do I set the 4 3D quad corner coordinates? I first tried with a quad but figured what I really needed was a cylinder, see the code in my answer, works just fine, and doesn't even use GLU at all, raw C. I edited this question, because my initial code was confussing and weird. My answer works, I repeat. Thanks!


Solution

  • Here is the adapted (from java) 'raw' C code I'm using to draw the cylinder:

    void getFirstPerpVector(float x, float y, float z, vec3_t result) 
    {
        result[0] = result[1] = result[2] = 0.0f;
        // That's easy.
        if (x == 0.0f || y == 0.0f || z == 0.0f) {
            if (x == 0.0f)
                result[0] = 1.0f;
            else if (y == 0.0f)
                result[1] = 1.0f;
            else
                result[2] = 1.0f;
        }
        else {
            // If xyz is all set, we set the z coordinate as first and second argument .
            // As the scalar product must be zero, we add the negated sum of x and y as third argument
            result[0] = z;      //scalp = z*x
            result[1] = z;      //scalp = z*(x+y)
            result[2] = -(x + y); //scalp = z*(x+y)-z*(x+y) = 0
            // Normalize vector
            float length = 0.0f;
            
            length += result[0] * result[0];
            length += result[1] * result[1];
            length += result[2] * result[2];
    
            length = (float)sqrt(length);
            for (int i = 0; i < 3; i++)
                result[i] /= length;
        }    
    }
    
    void drawCylinder(float x1, float y1, float z1, float x2, float y2, float z2, float thick, col_t color) 
    {
        int X = 0,
            Y = 1,
            Z = 2;
        // Get components of difference vector
        float x = x1 - x2,
            y = y1 - y2,
            z = z1 - z2;
        vec3_t firstPerp;
        getFirstPerpVector(x, y, z, firstPerp);
        // Get the second perp vector by cross product
        vec3_t secondPerp;
        secondPerp[X] = y * firstPerp[Z] - z * firstPerp[Y];
        secondPerp[Y] = z * firstPerp[X] - x * firstPerp[Z];
        secondPerp[Z] = x * firstPerp[Y] - y * firstPerp[X];
        // Normalize vector
        float length = 0.0f;
        
        length += secondPerp[0] * secondPerp[0];
        length += secondPerp[1] * secondPerp[1];
        length += secondPerp[2] * secondPerp[2];
    
        length = (float)sqrt(length);
        for (int i = 0; i < 3; i++)
            secondPerp[i] /= length;
    
        // Having now our vectors, here we go:
        // First points; you can have a cone if you change the radius R1
        int ANZ = C_CYLINDER_NUM_VERTICES;  // number of vertices Original 32
        float FULL = (float)(2.0f * M_PI),
            R1 = thick;// 2.0f; // radius Original 4.0f
        
        float points[C_CYLINDER_NUM_VERTICES + 1][3]; // 32 was ANZ
        for (int i = 0; i < ANZ; i++) {
            float angle = FULL * (i / (float)ANZ);
    
            points[i][X] = (float)(R1 * (cos(angle) * firstPerp[X] + sin(angle) * secondPerp[X]));
            points[i][Y] = (float)(R1 * (cos(angle) * firstPerp[Y] + sin(angle) * secondPerp[Y]));
            points[i][Z] = (float)(R1 * (cos(angle) * firstPerp[Z] + sin(angle) * secondPerp[Z]));
        }
        // Set last to first
        for (int x = 0; x < 3; x++)
            points[ANZ][x] = points[0][x];
        
        glColor4ubv(color);
        glBegin(GL_TRIANGLE_FAN);
        glVertex3f(x1, y1, z1);
        for (int i = 0; i <= ANZ; i++) {
            glVertex3f(x1 + points[i][X],
                y1 + points[i][Y],
                z1 + points[i][Z]);
        }
        glEnd();
    
        glBegin(GL_TRIANGLE_FAN);
        glVertex3f(x2, y2, z2);
        for (int i = 0; i <= ANZ; i++) {
            glVertex3f(x2 + points[i][X],
                y2 + points[i][Y],
                z2 + points[i][Z]);
        }
        glEnd();
    
        glBegin(GL_QUAD_STRIP);
        for (int i = 0; i <= ANZ; i++) {
            glVertex3f(x1 + points[i][X],
                y1 + points[i][Y],
                z1 + points[i][Z]);
            glVertex3f(x2 + points[i][X],
                y2 + points[i][Y],
                z2 + points[i][Z]);
        }
        glEnd();
    }