如何在具有正投影的OpenGL Core 3.3中绘制圆?

时间:2019-12-22 00:04:57

标签: c++ opengl glfw glew

我是OpenGL编程的完整入门者,正在尝试遵循learnopengl.com的Breakout教程,但希望将球绘制为实际的圆,而不是使用Joey建议的纹理四边形。但是,Google针对“ draw circle opengl 3.3”或类似短语抛出的所有结果似乎都至少存在了几年,并且使用了比该版本还要早的API:-(

我找到的最接近的东西是this SO question,但是OP只是必须使用自定义的VertexFormat对象来抽象一些细节,而没有分享他/她的实现!只是我的运气! :P

还有this YouTube tutorial使用了看似较旧的API版本,但是逐字复制代码(除了最后几行代码看起来很旧),我还是一无所获。

该教程中我的SpriteRenderer::initRenderData()版本:

void SpriteRenderer::initRenderData() {
    GLuint vbo;

    auto attribSize = 0;
    GLfloat* vertices = nullptr;

    // Determine whether this sprite is a circle or
    // quad and setup the vertices array accordingly
    if (!this->isCircle) {
        attribSize = 4;
        vertices = new GLfloat[24] {...}   // works for rendering quads
    } else {
        // This code is adapted from the YouTube tutorial that I linked
        // above and is where things go pear-shaped for me...or at least
        // **not** circle-shaped :P
        attribSize = 3;

        GLfloat x = 0.0f;
        GLfloat y = 0.0f;
        GLfloat z = 0.0f;
        GLfloat r = 100.0f;

        GLint numSides = 6;
        GLint numVertices = numSides + 2;

        GLfloat* xCoords = new GLfloat[numVertices];
        GLfloat* yCoords = new GLfloat[numVertices];
        GLfloat* zCoords = new GLfloat[numVertices];

        xCoords[0] = x;
        yCoords[0] = y;
        zCoords[0] = z;

        for (auto i = 1; i < numVertices; i++) {
            xCoords[i] = x + (r * cos(i * (M_PI * 2.0f) / numSides));
            yCoords[i] = y + (r * sin(i * (M_PI * 2.0f) / numSides));
            zCoords[i] = z;
        }

        vertices = new GLfloat[numVertices * 3];
        for (auto i = 0; i < numVertices; i++) {
            vertices[i * 3] = xCoords[i];
            vertices[i * 3 + 1] = yCoords[i];
            vertices[i * 3 + 2] = zCoords[i];
        }
    }

    // This is where I go back to the learnopengl.com code. Once
    // again, the following works for quads but not circles!
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(
        GLfloat), vertices, GL_STATIC_DRAW);

    glBindVertexArray(vao);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(0, attribSize, GL_FLOAT, GL_FALSE,
        attribSize * sizeof(GLfloat), (GLvoid*)0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

这是SpriteRenderer::DrawSprite()方法(与原始方法的唯一区别是第24-28行):

void SpriteRenderer::Draw(vec2 position, vec2 size, GLfloat rotation, vec3 colour) {
    // Prepare transformations
    shader.Use();

    auto model = mat4(1.0f);
    model = translate(model, vec3(position, 0.0f));

    model = translate(model, vec3(0.5f * size.x, 0.5f * size.y, 0.0f));   // Move origin of rotation to center
    model = rotate(model, rotation, vec3(0.0f, 0.0f, 1.0f));              // Rotate quad
    model = translate(model, vec3(-0.5f * size.x, -0.5f * size.y, 0.0f)); // Move origin back

    model = scale(model, vec3(size, 1.0f)); // Lastly, scale

    shader.SetMatrix4("model", model);

    // Render textured quad
    shader.SetVector3f("spriteColour", colour);

    glActiveTexture(GL_TEXTURE0);
    texture.Bind();

    glBindVertexArray(vao);

    if (!isCircular) {
        glDrawArrays(GL_TRIANGLES, 0, 6);
    } else {
        glDrawArrays(GL_TRIANGLE_FAN, 0, 24);  // also tried "12" and "8" for the last param, to no avail
    }

    glBindVertexArray(0);
}

最后,着色器(与用于四边形的着色器不同):

// Vertex shader
#version 330 core

layout (location = 0) in vec3 position;

uniform mat4 model;
uniform mat4 projection;

void main() {
    gl_Position = projection * model *
        vec4(position.xyz, 1.0f);
}

// Fragment shader
#version 330 core

out vec4 colour;

uniform vec3 spriteColour;

void main() {    
    colour = vec4(spriteColour, 1.0);
}

P.S。我知道我可以只使用四边形,但是我正在尝试学习如何在OpenGL中绘制 all 基本体,而不仅仅是四边形和三角形(无论如何,要感谢Joey)!

PPS我刚刚意识到,learnopengl.com网站上有一整节专门用于调试OpenGL应用程序,因此我进行了设置,但无济于事:-(我不认为错误处理受驱动程序支持(Intel按照说明,未设置GL_CONTEXT_FLAG_DEBUG_BIT,因为UHD Graphics 620是最新的驱动程序:

  

在GLFW中请求调试上下文非常容易,因为我们要做的就是向GLFW传递一个我们希望拥有调试输出上下文的提示。我们必须在调用glfwCreateWindow之前执行此操作:

     

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT,GL_TRUE);

     

一旦我们初始化GLFW,如果我们使用的是OpenGL 4.3或更高版本,我们应该有一个调试上下文,否则我们必须抓住机会,希望系统仍然能够请求调试上下文。否则,我们必须使用其OpenGL扩展请求调试输出。

     

要检查是否成功初始化了调试上下文,我们可以查询OpenGL:

     

GLint标志; glGetIntegerv(GL_CONTEXT_FLAGS,&flags);

     

if(标志和GL_CONTEXT_FLAG_DEBUG_BIT){       //初始化调试输出   }

从未输入过该if语句!

1 个答案:

答案 0 :(得分:0)

感谢@Mykola对this question的回答,我已经中途了:

    int status = std::system("ls -l >test.txt"); // execute the UNIX command "ls -l >test.txt"
    std::cout << std::ifstream("test.txt").rdbuf();
    std::cout << "Exit code: " << WEXITSTATUS(status) << std::endl;

哪个给了我this

我还有两个问题:

  1. 为什么从中心到右侧有多余的线,我该如何解决?
  2. 根据相关SO答案上的@user1118321's comment,我应该能够在数组的(0,0)处添加另一个顶点,并使用numVertices = 43; vertices = new GLfloat[numVertices]; auto i = 2; auto x = 0.0f, y = x, z = x, r = 0.3f; auto numSides = 21; auto TWO_PI = 2.0f * M_PI; auto increment = TWO_PI / numSides; for (auto angle = 0.0f; angle <= TWO_PI; angle += increment) { vertices[i++] = r * cos(angle) + x; vertices[i++] = r * sin(angle) + y; } 代替GL_TRIANGLE_FAN 得到一个彩色的圆圈。但这对我来说没有输出结果:-(为什么?