Есть несколько таких вопросов, но я до сих пор не совсем понял. Я кодировал OpenGL более 10 лет назад и заметил, как трудно попасть в современный OpenGL. Страница OpenGL.org - ужасный беспорядок, когда дело доходит до примеров, вы никогда не знаете, какая версия, любая версия, кажется, смешивается в различных примерах кода. Хорошо, у меня есть старый код, который я хочу обновить до OpenGL> 3, по крайней мере. Итак, первое, что я сделал, это перейти от glVertex3fv, чтобы, наконец, сделать это с помощью glVertexAttribPointer (над шагом с glVertexPointer, пока я не прочитаю это тоже устарело). Это работает отлично, но при попытке разместить текстуры я быстро застрял, и я полагаю, что это из-за неправильного позиционирования, и я хотел избавиться от кода c++:
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0 );
и сделать это
// bind vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_STATIC_DRAW);
// enable arrays
glEnableVertexAttribArray(0);
// set pointers
glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);
// render ComplexSurface
glDrawArrays(GL_TRIANGLE_FAN, 0, size);
glDisableVertexAttribArray(0);
с в vertexshader
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
И все работает волшебным образом. Теперь не поймите меня неправильно, я большой поклонник магии, но... Затем я нашел пару матричных преобразований, которые можно использовать для получения матрицы для замены glFrustum, но всякий раз, когда я пытаюсь ее заменить, (хотя я думаю, что понял математику за glFrustum и преобразование в матрицу).
Что пробовали что-то вроде
buildPerspProjMat(g_ProjView,FovAngle,Aspect,1.0,32768.0 );
glUseProgram(g_program);
glUniformMatrix4fv(g_programFrustum, 1, GL_FALSE, g_ProjView );
glUseProgram(0);
и используя положение в шейдере из вышеприведенного буфера с помощью проекционного матикса, но это совсем не работает.
Так что я просто не понимаю, где заменить это и на что в шейдере. Я не знаю, в какой момент происходит glMatrixMode и "когда" заменить его на некоторую однородную матрицу (передача аргументов как однородная не является проблемой здесь). Я не могу подсчитать, сколько учебников я прочитал уже, но я всегда путаюсь со всеми смешанными версиями. Я всегда рад некоторым примерам кода, но, пожалуйста, OpenGL 3 или выше.
Следующей будет замена glTexCoord2f для текстурирования, но это другая история :)
Я нахожу, что, думая о современном OpenGL, лучше забыть, что glMatrixMode
когда-либо существовал.
Имея это в виду, отпустите все, что вам нужно для самой основной операции рисования: замена gl_ModelViewProjectionMatrix
. Как следует из названия, это комбинация из трех разных матриц: матрица моделей, матрица представлений и матрица проекции.
Так что вам понадобится в вашем шейдере, чтобы разместить это 3 равномерные переменные типа mat4
. Что вы будете использовать так:
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
layout (location = 0) in vec3 position;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(position, 1.0);
}
Этот бит шейдерного кода выполняет ту же функцию, что и тот, который у вас был выше. Что изменилось, так это то, что встроенная gl_ModelViewProjectionMatrix
была заменена тремя равномерными переменными (которые можно было бы объединить в один, если вы обязательно их размножаете на стороне C++, прежде чем передавать его). И встроенный gl_Vertex
был заменен входной переменной.
На стороне C++ вам нужно будет сделать 2 вещи. Сначала вам нужно будет найти место для каждой из этих мундиров:
GLuint modelMatIdx = glGetUniformLocation(shaderProgId, "modelMat");
GLuint viewMatIdx = glGetUniformLocation(shaderProgId, "viewMat");
GLuint projMatIdx = glGetUniformLocation(shaderProgId, "projMat");
И с этим в руке вы можете теперь передать значения для каждого равномерного правого перед рисованием с помощью glUniformMatrix4fv
.
Одной конкретной библиотекой, которая делает это особенно легко, является glm. Например, чтобы получить ту же матрицу проекций, что и в вашем примере, вы должны:
glm::mat4 projMat = glm::frustum(-RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0);
и вы передадите его так:
glUniformMatrix4fv(projMatIdx, 1, GL_FALSE, glm::value_ptr(projMat));
Теперь, когда вы знаете, как это сделать, я хотел бы затронуть вопрос "когда". Вы сказали, что не знаете, что такое матричный режим, и это возвращает меня к моему предыдущему утверждению "забыть об этом". Матричный режим был там, так что вы могли бы сказать, что opengl, на который встроен, должен быть затронут вызовами операций с матрицей OpenGL, такими как glTranslate, glFrustum и т.д., Но все это уже не так. Теперь вы отвечаете за управление (возможно, многими) матрицами. Все, что вам нужно сделать, это передать их, прежде чем рисовать (как я показал выше), и все будет в порядке. Просто убедитесь, что программа связана, прежде чем пытаться изменить форму.
Вот рабочий пример (если вы suprised gl ::... вместо gl... это потому, что я использую заголовок opengl, сгенерированный glLoadGen, который помещает все функции API opengl в пространство имен gl).
GLuint simpleProgramID;
// load the shader and make the program
GLuint modelMatIdx = gl::GetUniformLocation(simpleProgramID, "modelMat");
GLuint viewMatIdx = gl::GetUniformLocation(simpleProgramID, "viewMat");
GLuint projMatIdx = gl::GetUniformLocation(simpleProgramID, "projMat");
GLuint vaoID;
gl::GenVertexArrays(1, &vaoID);
gl::BindVertexArray(vaoID);
GLuint vertBufferID, indexBufferID;
gl::GenBuffers(1, &vertBufferID);
gl::GenBuffers(1, &indexBufferID);
struct Vec2 { float x, y; };
struct Vec3 { float x, y, z; };
struct Vert { Vec3 pos; Vec2 tex; };
std::array<Vert, 8> cubeVerts = {{
{ { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f } }, { { 0.5f, 0.5f, -0.5f }, { 1.0f, 1.0f } },
{ { 0.5f, -0.5f, -0.5f }, { 0.0f, 1.0f } }, { { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f } },
{ { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f } }, { { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f } },
{ { -0.5f, -0.5f, -0.5f }, { 1.0f, 1.0f } }, { { -0.5f, -0.5f, 0.5f }, { 1.0f, 0.0f } }
}};
std::array<unsigned int, 36> cubeIdxs = {{
0, 2, 1, 0, 3, 2, // Right
4, 5, 6, 4, 6, 7, // Left
0, 7, 3, 0, 4, 7, // Top
1, 6, 2, 1, 5, 6, // Bottom
0, 5, 1, 0, 4, 5, // Front
3, 7, 6, 3, 6, 2 // Back
}};
// Vertex buffer
gl::BindBuffer(gl::ARRAY_BUFFER, vertBufferID);
gl::BufferData(gl::ARRAY_BUFFER, sizeof(Vert) * cubeVerts.size(), cubeVerts.data(), gl::STATIC_DRAW);
gl::EnableVertexAttribArray(0); // Matches layout (location = 0)
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE_, sizeof(Vert), 0);
gl::EnableVertexAttribArray(1); // Matches layout (location = 1)
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE_, sizeof(Vert), (GLvoid*)sizeof(Vec3));
// Index buffer
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indexBufferID);
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * cubeIdxs.size(), cubeIdxs.data(), gl::STATIC_DRAW);
gl::BindVertexArray(0);
glm::mat4 projMat = glm::perspective(56.25f, 16.0f/9.0f, 0.1f, 100.0f);
glm::mat4 viewMat = glm::lookAt(glm::vec3(5, 5, 5), glm::vec3(0, 0, 0), glm::vec3(0, 0, 1));
glm::mat4 modelMat; // identity
while (!glfwWindowShouldClose(window))
{
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
gl::UseProgram(simpleProgramID);
gl::UniformMatrix4fv(projMatIdx, 1, gl::FALSE_, glm::value_ptr(projMat));
gl::UniformMatrix4fv(viewMatIdx, 1, gl::FALSE_, glm::value_ptr(viewMat));
gl::UniformMatrix4fv(modelMatIdx, 1, gl::FALSE_, glm::value_ptr(modelMat));
gl::BindVertexArray(vaoID);
gl::DrawElements(gl::TRIANGLES, 36, gl::UNSIGNED_INT, 0);
gl::BindVertexArray(0);
gl::UseProgram(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
Связанный вершинный шейдер:
//[VERTEX SHADER]
#version 430
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
layout (location = 0) in vec3 in_position; // matches gl::EnableVertexAttribArray(0);
layout (location = 1) in vec2 in_uv; // matches gl::EnableVertexAttribArray(1);
out vec2 uv;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(in_position, 1.0);
uv = in_uv;
}
И, наконец, Fragment shader:
//[FRAGMENT SHADER]
#version 430
in vec2 uv;
out vec4 color;
void main()
{
color = vec4(uv, 0.0, 1.0);
}
Полученное изображение:
Ну, я согласен с тем, что большинство обучающих программ OpenGL путают бит устаревших и не устаревших вещей. Позвольте мне объяснить вам правильное направление.
gl_ModelViewProjectionMatrix
, gl_ModeView
, glMatrixMode()
и матричный стек glPushMatrix()
glPopMatrix()
устарели. Вы должны определить свои собственные матрицы как однородные переменные, а затем установить их и передать их glUniform*
с помощью glUniform*
.
gl_Vertex
также устарел, на самом деле все имена фиксированных атрибутов устарели. Кроме того, вам необходимо определить свои собственные имена атрибутов и привязать их к определенным местоположениям. Затем вы можете установить свои значения с помощью glVertexAttribPointer
, передав ему местоположение атрибута (полное объяснение здесь). Например:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); // for vertices
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, color); // for color
И для шейдерного кода
layout (location = 0) in vec4 vertex;
layout (location = 1) in vec4 color;
uniform mat4 modelview;
uniform mat4 projection;
void main()
{
gl_Position = projection* modelview* vertex;
}
Для местоположений атрибутов вы можете установить их в коде шейдера, как я, или из OpenGL API, используя glBindAttribLocation.
Управление однородными переменными может быть каким-то сложным, если вы привыкли к старым переменным globals OpenGL, таким как gl_ModelView
Я написал статью, которая, надеюсь, поможет вам управлять однородными переменными для большого проекта.
GL_QUADS
, например!)