Мне нужна помощь с рендерингом перевернутой сцены в кадровый буфер. Я хочу сделать зеркальный эффект.
Что я имею в результате:
Инициализация кадрового буфера:
GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_NONE);
Рисуем сцену в буфер кадра:
mView = camera.getViewMatrix();
mProjection = perspective(45.0f, 4.0f / 3.0f, 0.1f, 300.0f) * scale(mat4(1.0f), vec3(1.0f, -1.0f, 1.0f));
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferName);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCullFace(GL_FRONT);
glEnable(GL_CULL_FACE);
mWorld = rotate(mWorld, -15.0f, vec3(1, 0, 0));
mWorld = rotate(mWorld, -30.0f, vec3(0, 1, 0));
cubemap.Draw(mView, mProjection, mWorld);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glUseProgram(program);
mWorld = translate(mat4(1.0f), vec3(0, -10, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
mWorld = mat4(1.0f);
mWorld = translate(mat4(1.0f), vec3(50, -10, 0));
mWorld = rotate(mWorld, 90.0f, vec3(0, 1, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
mWorld = mat4(1.0f);
mWorld = translate(mat4(1.0f), vec3(0, -10, 50));
mWorld = rotate(mWorld, 140.0f, vec3(0, 1, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
glDisable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Я видел несколько уроков, где использовали glScalef (1.0, -1.0, 1.0) для инвертирования сцены.
glScalef использовался в старых версиях opengl. Как я могу инвертировать сцену в новых версиях OpenGL?
Я умножил матрицу проекции на масштаб (mat4 (1.0f), vec3 (1.0, -1.0, 1.0)) для этого эффекта. Это правильно?
Вот вершинный шейдер, написанный на GLSL.
void main(void)
{
// Clean up inaccuracies
vec2 Pos = sign(gl_Vertex.xy);
gl_Position = vec4(Pos.xy, 0.0, 1.0);
// Image-space
gl_TexCoord[0].xy = vec2(-Pos.x, Pos.y) * 0.5 + 0.5; // x texture coord is inverted
}
Pos
относится к выравниванию по экрану для вывода кадрового буфера.
Фрагмент шейдера
uniform sampler2D framebufferSampler;
void main(void)
{
gl_FragColor = texture2D(framebufferSampler, gl_TexCoord[0].xy);
}
Выровненный по экрану квад может быть нарисован
glBegin(GL_QUADS)
{
glVertex2f(-1.0f, -1.0f);
glVertex2f(1.0f, -1.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
}
glEnd();
или используя массивы вершин.
GLfloat vertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, (void*)vertices);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
Текстура, которая используется для переноса в квад, является информацией кадрового буфера с предыдущим визуализированным контентом (техника многопроходного шейдера).
Вы также можете сделать это с другими 2D текстурными координатами или изображениями вместо кадрового буфера и выравнивания экрана.
Исходное изображение.
Перевернутое изображение.
Более подробную информацию можно найти в Изучите OpenGL.
Других решений пока нет …