Я стряхнул приложение, которое использует API старого стиля OpenGL 1.2 и хочу обновить приложение для использования OpenGL 4.5 и, в частности, использовать бесконтактное управление состояниями с помощью прямого доступа к состоянию, потому что, кажется, - в теория - это облегчит управление состоянием визуализируемого объекта с меньшим случайным перегибом между объектами.
Я пытаюсь получить абсолютную реализацию треугольника только для DSA, но треугольник не отображается и при использовании glUseProgram (0) конвейер с фиксированной функциональностью не «возвращается к сервису», поэтому остальные устаревшие объекты также исчезают.
Основное приложение создает два экземпляра треугольника - каждый получает свой собственный объект массива вершин, программный объект, буфер индекса и буфер позиции вершины. Поскольку это работает, у программных объектов есть идентичный код шейдера, но часть упражнения состоит в том, чтобы продемонстрировать, что я могу изменять программные объекты так, чтобы другие визуализированные объекты в приложении не затрагивались. Два экземпляра треугольника отличаются только тем, что они получают различное значение во время создания экземпляра, которое используется для смещения треугольника в X, поэтому два треугольника должны отображаться рядом друг с другом. Во время цикла рендеринга значение cycli c перемещает треугольник вверх и вниз по Y. Окно просмотра устанавливается в основной части приложения с помощью glViewport, а рендеринг выполняется в кадровый буфер по умолчанию.
Во время инициализации :
- Шейдеры скомпилированы и связаны. Вершинный шейдер принимает один атрибут позиции
- Выделен массив позиций вершин (но данные о положении еще не загружены)
- Массив индекса создан и данные индекса загружены
Один раз за кадр:
- Программа и объект массива вершин используются / связаны
- Данные позиции вершин обновляются, загружаются, и буфер привязывается к точке привязки буфера (индекс 0)
- Формат атрибута установлен и связан с этим индексом привязки
- Буфер индекса связан с vao с помощью glVertexArrayElementBuffer (и не привязывается к GL_ELEMENT_ARRAY_BUFFER)
- Выпущена команда 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_);
}