绘制球体OpenGL C++

Posted

技术标签:

【中文标题】绘制球体OpenGL C++【英文标题】:Draw sphere OpenGL C++ 【发布时间】:2020-11-16 12:28:15 【问题描述】:

我正在尝试使用 OpenGL 和 C++ 绘制一个球体,但我不能使用 glut Sphere 函数。我传递坐标(x,y,z),白色(1.0f,1.0f,1.0f)并顺序保存在顶点数组(顶点)中。

/** Vertex shader. */
const char *vertex_code = "\n"
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 color;\n"
"\n"
"out vec3 vColor;\n"
"\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"\n"
"void main()\n"
"\n"
"    gl_Position = projection * view * model * vec4(position, 1.0);\n"
"    vColor = color;\n"
"\0";

/** Fragment shader. */
const char *fragment_code = "\n"
"#version 330 core\n"
"\n"
"in vec3 vColor;\n"
"out vec4 FragColor;\n"
"\n"
"void main()\n"
"\n"
"    FragColor = vec4(vColor, 1.0f);\n"
"\0";
void display()

    glClearColor(0.2, 0.3, 0.3, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(program);
    
    // Define view matrix.
    glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f));

    // Retrieve location of tranform variable in shader.
    unsigned int loc = glGetUniformLocation(program, "view");
    // Send matrix to shader.
    glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(view));

    // Define projection matrix.
    glm::mat4 projection = glm::perspective(glm::radians(60.0f), (win_width/(float)win_height), 0.1f, 100.0f);
    
    // Retrieve location of tranform variable in shader.    
    loc = glGetUniformLocation(program, "projection");
    
    // Send matrix to shader.
    glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(projection));
    
    // Pyramid
    glBindVertexArray(VAO2);

    // Define model matrix.
    glm::mat4 S  = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f, 1.0f, 1.0f));
    glm::mat4 Rx = glm::rotate(glm::mat4(1.0f), glm::radians(px_angle), glm::vec3(1.0f,0.0f,0.0f));
    glm::mat4 Ry = glm::rotate(glm::mat4(1.0f), glm::radians(py_angle), glm::vec3(0.0f,1.0f,0.0f));
    glm::mat4 T  = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f));
    glm::mat4 model = T*Ry*Rx*S;

    // Retrieve location of tranform variable in shader.
    loc = glGetUniformLocation(program, "model");
    
    // Send matrix to shader.
    glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glDrawArrays(GL_POINTS, 0, 10 * 20 * 20);
        
    glutSwapBuffers();

void initData(float radius, float stacks, float sectors)

float *vertices;
    int quantidade = 0;

    vertices = (float *) malloc(radius * stacks * sectors * 6 * sizeof(float));

    if(!vertices)
        printf("Erro ao alocar memória!\n");
        exit(-1);
    

    const float pi = 3.14159265359;
    const float deltaPhi = pi/stacks;
    const float deltaTheta = (2 * pi)/sectors;

    for(int i=0; i<=stacks; i++)

        float phi = (-pi / 2.0) + (i * deltaPhi);
        float temp = radius * cos(phi);
        float z = radius * sin(phi);

        for(int j=0; j<=sectors; j++)

            float theta = j * deltaTheta;
            float y = temp * sin(theta);
            float x = temp * cos(theta);

            // normalize
            x = x / radius;
            y = y / radius;
            z = z / radius;

            vertices[quantidade++] = x;
            vertices[quantidade++] = y;
            vertices[quantidade++] = z;
            vertices[quantidade++] = 1.0f;
            vertices[quantidade++] = 1.0f;
            vertices[quantidade++] = 1.0f;
        
    

    // Vertex array.
    glGenVertexArrays(1, &VAO2);
    glBindVertexArray(VAO2);

    // Vertex buffer
    glGenBuffers(1, &VBO2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * radius * stacks * sectors * 6, vertices, GL_STATIC_DRAW);
    
    // Set attributes.
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
    glEnableVertexAttribArray(1);

    // Unbind Vertex Array Object.
    glBindVertexArray(0);
    
    glEnable(GL_DEPTH_TEST);
int main(int argc, char** argv)

    glutInit(&argc, argv);
    glutInitContextVersion(3, 3);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(win_width,win_height);
    glutCreateWindow(argv[0]);
    glewExperimental = GL_TRUE;
    glewInit();

    // Init vertex data for the sphere
    initData(10.0, 20.0, 20.0);

    // Create shaders.
    initShaders();
    
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    //glutIdleFunc(idle);

    glutMainLoop();

最后的结果是这样的:

https://i.imgur.com/b7EwhVG.png

https://i.imgur.com/Piopsgw.png

我做错了什么?我使用此链接 (http://www.songho.ca/opengl/gl_sphere.html) 作为参考。

【问题讨论】:

你只有6 * (stacks + 1) * (sectors + 1)点,为什么分配(和绘制)更多? radius 在那里做的额外乘法是什么? @Botje 我正在做一些实验,看看它是否有效。分配内存时和 glBufferData 函数中已更改为 6 * (stacks + 1) * (sectors + 1) * sizeof(float)。还有 glDrawArrays 现在我正在传递 (stacks + 1) * (sectors + 1) 点。但它仍然在做与图片中显示的相同的事情 尝试转储 vertices 的内容,例如 i=5。代表完整的圆圈吗? 是的。我在第一个 for 循环中开始 i=5 ,奇怪的是结果仍然相同。但是,如果我在第二个 for 循环中开始 j=5,则圆圈不再完全表示。 不,直接检查vertices的内容,不渲染。这样您就可以确定您的积分生成至少是正确的。 【参考方案1】:
void desenhaEsfera(int nx, int ny) 

    float alfa, beta;
    float x1, y1, z1, x2, y2, z2;

    alfa = (2*pi)/nx;
    beta = pi/ny;

    glPolygonMode(GL_FRONT, GL_LINE);
    
    for(int j=0; j<=ny; j++)
        glBegin(GL_TRIANGLE_STRIP);
        for(int i=0; i<=nx; i++)
            x1 = cos(alfa*i)*sin(beta*j);
            y1 = cos(beta*j);
            z1 = sin(alfa*i)*sin(beta*j);

            x2 = cos(alfa*i)*sin(beta*(j+1));
            y2 = cos(beta*(j+1));
            z2 = sin(alfa*i)*sin(beta*(j+1));

            glNormal3f(x1, y1, z1);
            glVertex3f(x1, y1, z1);
            glNormal3f(x2, y2, z2);
            glVertex3f(x2, y2, z2);
        
        glEnd();
       

【讨论】:

以上是关于绘制球体OpenGL C++的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenGL 4.0 中绘制球体

OPENGL初学

在 C++ 中的 OpenGL 中将坐标从 3D 透视投影映射到 2D 正交投影

OpenGL:球体减慢帧速率

用 Opengl 画一个球体

如何在 C++ 中按递增顺序绘制球体网格?