Я не могу заставить мой треугольник OpenGL 4.5 "hello-world" появляться с использованием установки объекта массива вершин только для прямого доступа к состоянию - PullRequest
0 голосов
/ 19 января 2020

Я стряхнул приложение, которое использует API старого стиля OpenGL 1.2 и хочу обновить приложение для использования OpenGL 4.5 и, в частности, использовать бесконтактное управление состояниями с помощью прямого доступа к состоянию, потому что, кажется, - в теория - это облегчит управление состоянием визуализируемого объекта с меньшим случайным перегибом между объектами.

Я пытаюсь получить абсолютную реализацию треугольника только для DSA, но треугольник не отображается и при использовании glUseProgram (0) конвейер с фиксированной функциональностью не «возвращается к сервису», поэтому остальные устаревшие объекты также исчезают.

Основное приложение создает два экземпляра треугольника - каждый получает свой собственный объект массива вершин, программный объект, буфер индекса и буфер позиции вершины. Поскольку это работает, у программных объектов есть идентичный код шейдера, но часть упражнения состоит в том, чтобы продемонстрировать, что я могу изменять программные объекты так, чтобы другие визуализированные объекты в приложении не затрагивались. Два экземпляра треугольника отличаются только тем, что они получают различное значение во время создания экземпляра, которое используется для смещения треугольника в X, поэтому два треугольника должны отображаться рядом друг с другом. Во время цикла рендеринга значение cycli c перемещает треугольник вверх и вниз по Y. Окно просмотра устанавливается в основной части приложения с помощью glViewport, а рендеринг выполняется в кадровый буфер по умолчанию.

Во время инициализации :

  1. Шейдеры скомпилированы и связаны. Вершинный шейдер принимает один атрибут позиции
  2. Выделен массив позиций вершин (но данные о положении еще не загружены)
  3. Массив индекса создан и данные индекса загружены

Один раз за кадр:

  1. Программа и объект массива вершин используются / связаны
  2. Данные позиции вершин обновляются, загружаются, и буфер привязывается к точке привязки буфера (индекс 0)
  3. Формат атрибута установлен и связан с этим индексом привязки
  4. Буфер индекса связан с vao с помощью glVertexArrayElementBuffer (и не привязывается к GL_ELEMENT_ARRAY_BUFFER)
  5. Выпущена команда Draw

Ни в коем случае я не использую glBindBuffer - суть в том, что я пытаюсь использовать только DSA, и мое [возможно, ошибочное?] Убеждение заключается в том, что путем установки vao без привязки с использованием только функций DSA, а затем При связывании этого vao с использованием glBindVertexArray все состояние станет «текущим». Обратите внимание, что этот намеренно наивный образец не использует матрицу проекции или матрицу вида модели - он нацелен на непосредственное создание треугольников в середине экрана, так же, как и в любом приложении первого треугольника в стиле «привет».

У меня есть проверенный контекст совместимости 4.5 GL, созданный с помощью WGL, компиляция шейдеров и ссылки на программы. Я агрессивно закодировал защиту и проверял glGetError буквально после каждого вызова (хотя я взял многие из них из кода здесь для удобства чтения).

Сообщенная версия GL - "4.5.0 NVIDIA 382.05" и Версия GLSL - "4.50 NVIDIA".

Я попытался привязать буфер индекса к точке привязки буфера GL_ELEMENT_ARRAY_BUFFER, чтобы увидеть, если это имеет значение, и это не работает. Я даже пытался связать буфер положения вершины с точкой привязки GL_ARRAY_BUFFER, но без неожиданности ничего не получилось.

Либо я упускаю что-то простое, либо моя концепция работы DSA слишком прославлена ​​и неверна , Что я могу попробовать дальше?

GlslTriangle.h:

#pragma once

#include <glad.h>

typedef unsigned short uint16;
typedef unsigned int uint32;

class GlslTriangle
{
private:
    int instance_{ 0 };

    GLuint prg_{ 0 };
    GLuint vao_{ 0 };
    GLuint vtx_{ 0 };
    GLuint idx_{ 0 };
    uint32 frameCount_{ 0 };

    GLuint CompileVtxShader();
    GLuint CompileFrgShader();
    void LinkProgram(GLuint v, GLuint f);
    void CreateBuffers();
    void ClearErr();
    void BreakIfErr();

public:

    GlslTriangle(int inst) :
        instance_(inst)
    {}

    void OneTimeInit();

    void Generate();

    void Render();

    void Deallocate();
};

GlglTriangle. cpp:

#include <stdafx.h>
using std::string;

#include <Geometry.h> //Point3f
#include <GlslTriangle.h>


void GlslTriangle::BreakIfErr()
{
    GLenum err;
    if ((err = glGetError()) != GL_NO_ERROR)
        assert(false);
}



void GlslTriangle::ClearErr()
{
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR)
    {
    }
}



GLuint GlslTriangle::CompileVtxShader()
{
    auto v = glCreateShader(GL_VERTEX_SHADER);
    BreakIfErr();

    string vsrc =
        "#version 450 core \n"\
        "layout(location = 0) in vec3 vertexPosition; \n"\
        "void main() \n"\
        "{ \n"\
        "gl_Position.xyz = vertexPosition; \n"\
        "gl_Position.w = 1.0; \n"\
        "} \n";

    auto vsrca = vsrc.c_str();
    GLint vsrcl = vsrc.length();

    glShaderSource(v, 1, &vsrca, &vsrcl);
    BreakIfErr();

    glCompileShader(v);
    BreakIfErr();

    GLint vstatus{ 0 };
    glGetShaderiv(v, GL_COMPILE_STATUS, &vstatus);
    assert(vstatus);

    return v;
}



GLuint GlslTriangle::CompileFrgShader()
{
    auto f = glCreateShader(GL_FRAGMENT_SHADER);
    string fsrc =
        "#version 450 core \n" \
        "out vec3 color; \n "\
        "void main() \n" \
        "{ \n"\
        "color = vec3(0.5, 0.5, 1.0); \n"\
        "} \n";

    auto fsrca = fsrc.c_str();
    GLint fsrcl = fsrc.length();

    glShaderSource(f, 1, &fsrca, &fsrcl);
    BreakIfErr();

    glCompileShader(f);
    BreakIfErr();

    GLint fstatus{ 0 };
    glGetShaderiv(f, GL_COMPILE_STATUS, &fstatus);
    assert(fstatus);

    return f;
}



void GlslTriangle::LinkProgram(GLuint v, GLuint f)
{
    glAttachShader(prg_, v);
    glAttachShader(prg_, f);
    glLinkProgram(prg_);
    BreakIfErr();

    GLint lstatus{ 0 };
    glGetProgramiv(prg_, GL_LINK_STATUS, &lstatus);
    assert(lstatus);

    glDetachShader(prg_, v);
    glDetachShader(prg_, f);
    glDeleteShader(v);
    glDeleteShader(f);
}



void GlslTriangle::CreateBuffers()
{
    //Allocate space for 3 points - we'll populate data later
    glCreateBuffers(1, &vtx_);
    glNamedBufferStorage(vtx_, 3 * sizeof(Point3f), nullptr, GL_DYNAMIC_STORAGE_BIT);
    BreakIfErr();

    //Allocate space for 3 indices
    glCreateBuffers(1, &idx_);
    uint16 i[3];
    i[0] = 0;
    i[1] = 1;
    i[2] = 2;

    //Upload index data
    glNamedBufferStorage(idx_, 3 * sizeof(uint16), i, GL_DYNAMIC_STORAGE_BIT);
    BreakIfErr();
}



void GlslTriangle::OneTimeInit()
{
    ClearErr();

    glCreateVertexArrays(1, &vao_);

    prg_ = glCreateProgram();
    BreakIfErr();

    auto v = CompileVtxShader();
    auto f = CompileFrgShader();
    LinkProgram(v, f);

    CreateBuffers();
}



void GlslTriangle::Generate()
{
    ClearErr();

    //Provide a cyclic value that will push the triangle up and down in Y
    float cycle{ 1000.0f };
    float offset = 5 * sin(2*PI *(float)frameCount_ / cycle);

    //The instance parameter is provided at instantiation of "this" and
    //just offsets the triangle - with 2 instances of "this" we should see 
    //two triangles at different positions in X

    Point3f data[3];
    data[0] = { -1.0f + (float)instance_, 0.0f + offset, 10.0f};
    data[1] = { 0.0f + (float)instance_, 1.0f + offset, 10.0f};
    data[2] = { 1.0f + (float)instance_, 0.0f + offset, 10.0f};

    GLintptr bo{ 0 }; //buffer offset
    glNamedBufferSubData(vtx_, bo, 3 * sizeof(Point3f), data);
    BreakIfErr();

    ++frameCount_;
    frameCount_ = frameCount_ == cycle ? 0 : frameCount_;
}



void GlslTriangle::Render()
{
    GL::ClearErr();

    GLfloat skyColor[4] = { 0.75f, 0.75f, 1.0f, 1.0f };
    glClearColor(skyColor[0], skyColor[1], skyColor[2], skyColor[3]);
    glClearDepth(100.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(prg_);
    glBindVertexArray(vao_);
    glVertexArrayElementBuffer(vao_, idx_);

    GLuint a{ 0 }; //attribute idx
    GLuint b{ 0 }; //binding idx
    GLintptr offset{ 0 }; //offset in buffer
    GLint c{ 3 }; //components
    GLuint r{ 0 }; //relative offset in buffer element

    glVertexArrayAttribFormat(vao_, a, c, GL_FLOAT, GL_FALSE, r);
    glVertexArrayVertexBuffer(vao_, b, vtx_, offset, sizeof(Point3f));
    glVertexArrayAttribBinding(vao_, a, b);
    glEnableVertexArrayAttrib(vao_, a);

    GLsizei e{ 3 }; //count of elements
    glDrawElements(GL_TRIANGLES, e, GL_UNSIGNED_SHORT, nullptr);

    BreakIfErr();

    glUseProgram(0);
}



void GlslTriangle::Deallocate()
{
    glDeleteProgram(prg_);
    glDeleteVertexArrays(1, &vao_);
    glDeleteBuffers(1, &vtx_);
    glDeleteBuffers(1, &idx_);
}

1 Ответ

3 голосов
/ 19 января 2020

Поскольку вы не используете матрицу проекции или преобразования, координаты вершины должны быть указаны в нормализованном пространстве устройства. Нормализованное пространство устройства - это куб с левым, нижним, ближним (-1, -1, -1) и правым верхним, дальним (1, 1, 1).
Вся геометрия, которая не находится внутри этот объем просмотра отсечен.

Ваша геометрия отсечена, поскольку все координаты z равны 10.0f.
Измените координаты z (например, 0.0f), чтобы решить проблему.

Примечание glClearDepth не указывает дальнюю плоскость объема просмотра. Он определяет значение, которое записывается в буфер глубины при его очистке glClear(GL_DEPTH_BUFFER_BIT) и должно находиться в диапазоне [0.0, 1.0]. По умолчанию это 1,0.
(см. glDepthRange и Проверка глубины )

...