如何使用圆柱体绘制完美的 3D Spring

How to draw a perfect 3D Spring using Cylinders

我正在尝试仅使用圆柱体绘制 Spring。

void spring(GLfloat rounds, GLfloat height, GLfloat thickness, GLfloat radius) {
    glColor3f(1.0, 1.0, 1.0);
    GLfloat j = 0;

    for (GLfloat i = 0; i <= rounds * 360; i += 5) {
        glPushMatrix();
        glRotatef(i, 0, 1, 0);
        glTranslatef(0, j, radius);
        gluCylinder(qobj, thickness, thickness, radius, 50, 50);
        glPopMatrix();

        j += height / (rounds * 360);
    }
}
spring(4, 2.5, 0.03, 0.1);

用这段代码绘制的spring并不完美。此外,当半径增加时,spring 的形状会变形。

我该如何解决这个问题?

A spring 是在 3 个维度上弯曲的形状。圆柱体不能完美地粘在一起形成 spring。为什么不使用 OpenGL 创建自己的网格 primitives

例如:使用 TRINGLESTRIP 将长丝带缠绕在弯曲成 spring 的管子上:

#include <vector>
#include <algorithm>
void createSpring(
    GLfloat rounds, GLfloat height, GLfloat thickness, GLfloat radius, 
    std::vector<GLfloat> &vertices, std::vector<GLuint> &indices)
{
    const int slices = 32;
    const int step = 5;
    for (int i = -slices; i <= rounds * 360 + step; i += step)
    {
        for (int j = 0; j < slices; j ++)
        {
            GLfloat t = (GLfloat)i / 360 + (GLfloat)j / slices * step / 360;
            t = std::max(0.0f, std::min(rounds, t));
            GLfloat a1 = t * M_PI * 2;
            GLfloat a2 = (GLfloat)j / slices * M_PI * 2;
            GLfloat d = radius + thickness * cos(a2);
            vertices.push_back(d * cos(a1));
            vertices.push_back(d * sin(a1));
            vertices.push_back(thickness * sin(a2) + height * t / rounds);
        }
    }
    for (GLuint i = 0; i < (GLuint)vertices.size() / 3 - slices; ++i)
    {
        indices.push_back(i);
        indices.push_back(i + slices);
    }
}
void drawSpring(
    const std::vector<GLfloat>& vertices, const std::vector<GLuint>& indices)
{
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // just to see the mesh (delete later)

    glColor4f(1, 1, 1, 1);
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, vertices.data());
    glDrawElements(GL_TRIANGLE_STRIP, indices.size(), GL_UNSIGNED_INT, indices.data());
    glDisableClientState(GL_VERTEX_ARRAY);
}
std::vector<GLfloat> springVertices;
std::vector<GLuint> springIndices;

void init()
{
    createSpring(1.5, 0.25, 0.03, 0.1, springVertices, springIndices);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(20.0, 1.0f, 0.1f, 1000);
    glMatrixMode(GL_MODELVIEW);
    gluLookAt(0, -1, 0.125, 0, 0.0, 0.125, 0, 0, 1);

    glEnable(GL_DEPTH_TEST);
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    drawSpring(springVertices, springIndices);
    glutPostRedisplay();
    glutSwapBuffers();
}