您如何使用GL_TRIANGLE_FAN在OpenGL中绘制圆?

问题描述 投票:0回答:1

季节问候大家!我改写了this tutorial中的代码以支持使用VAO / VBO,但现在我明白了:

weirdest circle ever

而不是一个漂亮的圆形圆圈。这是代码:

#define GLEW_STATIC

#include <GLEW/glew.h>
#include <GLFW/glfw3.h>

#include <corecrt_math_defines.h>
#include <cmath>
#include <vector>

#define SCREEN_WIDTH 3000
#define SCREEN_HEIGHT 1900

void drawPolygon(GLuint& vao, GLuint& vbo, GLfloat x,
    GLfloat y, GLdouble radius, GLint numberOfSides);

int main(void) {
    if (!glfwInit()) {
        return -1;
    }

    GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH,
        SCREEN_HEIGHT, "Hello World", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    glewInit();
    glGetError();

    glViewport(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT);

    GLuint vao, vbo;
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT, -1, 1);

    while (!glfwWindowShouldClose(window)) {
        glClear(GL_COLOR_BUFFER_BIT);
        drawPolygon(vao, vbo, SCREEN_WIDTH / 2,
            SCREEN_HEIGHT / 2, 250.0f, 50);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

void drawPolygon(GLuint& vao, GLuint& vbo, GLfloat x,
    GLfloat y, GLdouble radius, GLint numberOfSides) {
    int numVertices = numberOfSides + 2;

    GLdouble twicePi = 2.0f * M_PI;

    vector<GLdouble> circleVerticesX;
    vector<GLdouble> circleVerticesY;

    circleVerticesX.push_back(x);
    circleVerticesY.push_back(y);

    for (int i = 1; i < numVertices; i++) {
        circleVerticesX.push_back(x + (radius *
            cos(i * twicePi / numberOfSides)));
        circleVerticesY.push_back(y + (radius *
            sin(i * twicePi / numberOfSides)));
    }

    vector<GLdouble> vertices;
    for (int i = 0; i < numVertices; i++) {
        vertices.push_back(circleVerticesX[i]);
        vertices.push_back(circleVerticesY[i]);
    }

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(
        GLdouble), vertices.data(), GL_STATIC_DRAW);
    glBindVertexArray(vao);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_DOUBLE, GL_FALSE,
        2 * sizeof(GLdouble), (void*)0);

    glDrawArrays(GL_TRIANGLE_FAN, 0, 27);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

我到底做错了什么?!使用the original code可以工作,所以我对这个荒谬的结果感到困惑! MTIA给任何可以帮助的人:-)

c++ opengl glfw glew
1个回答
1
投票

您的VBO的大小为numVertices * sizeof(GLdouble),它是顶点数据的实际大小的一半(每个顶点都有一个x y分量)。因此,最终绘制的顶点是VBO实际具有顶点数据的两倍。读取VBO的边界时,在OpenGL实现中恰好导致零,这就是为什么圆下半部分的所有顶点都在左下角的原因…

注释夫妇:

  • 您通常不需要使用double,除非需要它。 double占用两倍的内存带宽,并且double的算术通常至少比float慢一点。特别是GPU是为float算术而构建的。尤其是在消费类GPU上,double算法比float慢[(明显)](一个数量级)。您实际上不需要中心点。由于圆是凸形的,因此您可以简单地将圆上的点之一用作风扇的中心顶点。
  • 这不一定是画圆的最有效方法(很多长而细的三角形;有关here的更多信息]
  • 您可能不想在每一帧中一次又一次地生成并上传您的顶点数据,除非它有所变化。
  • 除此之外,您可能希望使glDrawArrays调用绘制顶点的实际数量,而不仅仅是总是27
© www.soinside.com 2019 - 2024. All rights reserved.