Замена для gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

0

Есть несколько таких вопросов, но я до сих пор не совсем понял. Я кодировал 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 для текстурирования, но это другая история :)

  • 0
    Теперь был еще один комментарий по этому поводу с довольно некоторой информацией, но он был удален несколько минут назад и вместо него был вставлен -1, но я не нашел времени скопировать ссылки и прочитать всю информацию. Я добавил еще немного информации в свой первоначальный вопрос, и это печально, что он был удален, потому что я не думаю, что это не соответствовало моему вопросу.
Теги:
opengl
glsl

2 ответа

12
Лучший ответ

Я нахожу, что, думая о современном 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);
}

Полученное изображение:

Изображение 174551

  • 0
    Спасибо, это уже ответило на многие вопросы. В вашем примере я теперь не уверен: glm :: mat4 modelMat; // идентичность - также я читал в нескольких уроках уже о GLM и использовал его в некоторых простых программах тестирования, но я чувствовал в первую очередь, что нужно изменить одну магию, которая работает против другой, которая не (в моей попытке) чтобы избавиться от gl_ModelViewProjectionMatrix по крайней мере), поэтому я хотел сначала избежать его использования. Думаю, теперь я понимаю, почему это не сработало.
  • 0
    СПАСИБО ТЕБЕ ЗА ЭТО! Я провел слишком много часов, пытаясь выяснить все это. Я не осознавал, сколько OpenGL, с которым я был знаком, устарело. Я очень расстроился, пытаясь понять, как заменить все устаревшие вещи. Кстати, изображение, которое я получаю, перевернуто по сравнению с вашим ... есть идеи, почему это может быть?
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 Я написал статью, которая, надеюсь, поможет вам управлять однородными переменными для большого проекта.

  • 0
    всегда хорошо иметь разные взгляды на одну и ту же тему, особенно когда дело доходит до понимания, и я думаю, что ваша статья может быть очень полезной для меня позже. Отлично, ты добавил это обратно.
  • 0
    Argh! Что не так с людьми Khronos? Снова и снова они показывают, что не понимают значения слова «осуждают». Это должно быть чем-то, что вы делаете, когда у вас есть лучшая замена для рассматриваемой функциональности, но они постоянно используют ее, чтобы вместо этого ухудшать ситуацию , взяв вещи, которые раньше просто «работали», и бросая их на колени, чтобы осуществить вручную, если это даже возможно. (Я до сих пор не видел хорошей замены для GL_QUADS , например!)
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню