Как нарисовать круг в OpenGL Core 3.3 с ортогональной проекцией? - PullRequest
0 голосов
/ 22 декабря 2019

Я - новичок в программировании OpenGL и пытаюсь следовать учебному пособию Breakout на learnopengl.com , но хотел бы нарисовать шар как реальный круг, вместо того чтобы использовать текстурированный квад, как Джоипредлагает. Тем не менее, каждый результат, который Google выдает мне за «Draw Circle OpenGL 3.3» или подобные фразы, кажется, по крайней мере, несколько лет, и использует даже более старые версии API: - (

Самая близкая вещь, которую я нашел, это этот вопрос , но, конечно, у ОП просто было , чтобы использовать пользовательский объект VertexFormat для абстрагирования некоторых деталей безподелился своей реализацией такой! Просто моя удача!: P

Также есть этот урок YouTube , который использует, казалось бы, более старую версию 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);
}

PS Я знаю, что могу просто использовать квад, но я пытаюсьЧтобы научиться рисовать все примитивы в OpenGL, а не только четырехугольники и треугольники (в любом случае, спасибо, Джои)!

PPS Я только что понял, что на сайте learnopengl.com есть целый раздел, посвященныйотлаживать приложения OpenGL, поэтому я настроил это, но безрезультатно :-( Я не думаю, что обработка ошибок поддерживается моим драйвером (последний драйвер Intel UHD Graphics 620), так как GL_CONTEXT_FLAG_DEBUG_BIT не был установлен после следования инструкциям:

Запрос контекста отладки в GLFW удивительно прост, так как все, что нам нужно сделать, - это передать GLFW подсказку о том, что нам бы хотелось иметь выходной контекст отладки. Мы должны сделать это прежде, чем мы вызовем glfwCreateWindow:

glfwWindowHint (GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

Как только мы инициализируем GLFW, у нас должен быть контекст отладки, если мы используем OpenGL версии 4.3 или выше, иначе мы должны рискнуть и надеяться, что система все еще сможет запросить контекст отладки. В противном случае мы должны запросить выходные данные отладки, используя расширение (я) OpenGL.

Чтобы проверить, успешно ли мы инициализировали контекст отладки, мы можем запросить OpenGL:

GLint flags;glGetIntegerv (GL_CONTEXT_FLAGS, & flags);

if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {// инициализировать выходные данные отладки}

Этот оператор if никогда не вводится!

1 Ответ

0 голосов
/ 22 декабря 2019

Благодаря ответу @ Mykola на этот вопрос Я попал туда на полпути:

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 комментарий к связанному SO-ответу, я должен иметь возможность добавить к вершине другую вершину в массиве (0, 0) и использовать GL_TRIANGLE_FAN вместо GL_LINE_LOOP, чтобы получить цветной круг. Но это не приводит к выводу для меня :-( Почему?
...