代码之家  ›  专栏  ›  技术社区  ›  Kenny83

如何在OpenGL Core 3.3中使用正交投影绘制圆?

  •  0
  • Kenny83  · 技术社区  · 6 年前

    我对OpenGL编程是一个完全的初学者,我正在努力学习 learnopengl.com 但是我想把球画成一个实际的圆,而不是像乔伊建议的那样使用有纹理的四边形。然而,谷歌因为“DrawCircle opengl 3.3”或类似短语而向我抛出的每一个结果似乎都至少有几年的历史了,而且使用的API版本甚至比那个版本还要旧:-(

    我找到的最接近的东西是 this SO question 当然,行动只是 使用自定义 VertexFormat 对象抽象了一些细节,没有分享他/她这样的实现!只是我的运气!:页

    还有 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、 我刚意识到learnopengl.com网站这个网站有一个专门调试OpenGL应用程序的部分,所以我设置了这个部分,但是没有用:-(我认为我的驱动程序(inteluhdgraphics620最新的驱动程序)不支持错误处理,因为 GL_CONTEXT_FLAG_DEBUG_BIT 未按照说明进行设置:

    在GLFW中请求一个调试上下文非常容易,因为我们所要做的就是向GLFW传递一个提示,表示我们想要一个调试输出上下文。在调用glfwCreateWindow之前,我们必须这样做:

    glfwWindowHint(GLFW\u OPENGL\u DEBUG\u CONTEXT,GL\u TRUE);

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

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

    GLint flags;glGetIntegerv(GL\u CONTEXT\u flags,&flags);

    if(标志和GL\u上下文\u标志\u调试\u位){

    if 声明永远不会被输入!

    0 回复  |  直到 6 年前
        1
  •  0
  •   Kenny83    6 年前

    感谢@Mykola对 this question

    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;
    }
    

    这让我 this .

    1. 为什么有一条额外的线从中间到右边,我怎么能修好它?
    2. 根据 @user1118321's comment 在一个相关的SO答案上,我应该能够在(0,0)处为数组预先设置另一个顶点,并使用 GL_TRIANGLE_FAN 而不是 GL_LINE_LOOP 得到一个彩色的圆圈。但这对我来说没有结果:-(为什么?
    推荐文章