LINUX.ORG.RU

Рендер нескольких текстур в FBO

 ,


0

1

Доброго времени суток,

Прошу помочь в следующей задаче:

Цель: Применить алгоритм сглаживания на отображаемую сцену. Исходные данные: AR проект, в котором при наведении на картинку начинает проигрываться анимация на экране. У каждого объекта анимации соответственно своя текстура и шейдер.

Пробовал реализовать двумя способами:

  1. Добавил реализацию алгоритма FXAA (http://www.geeks3d.com/20110405/fxaa...eon-geforce/3/) в шейдер каждой из текстур, однако сглаживание не применялось. Проверял следующим образом: делал скрин экрана и увеличивал, сглаживание не было. Поправьте, пожалуйста, если я не прав, но как я понял, такой подход не будет работать потому как в нем алгоритм применялся на каждую текстуру отдельно.

  2. Решил попробовать следующий вариант: сделать рендер всех объектов в одну текстуру, и потом применить алгоритм сглаживания к этой текстуре. Поэтому создал FBO, перед функцией рендеринга устанавливаю framebuffer в созданный, а после функции рендеринга сбрасываю framebuffer. Потом отображаю текстуру на экран. В результате я вижу только черный экран.

Используемый код:

1. Создаю FBO следующим образом:

void Initialize()
{
    glGenFramebuffers(1, &object);
 
    glGenTextures(1, &texture_map);
 
    //glGenRenderbuffers(1, &renderBufferId);
 
    glBindFramebuffer(GL_FRAMEBUFFER, object);
 
    glActiveTexture (GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture_map);
 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1080, 1920, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    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_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
    //glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
    //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_map, 0);
 
    //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBufferId);
 
    glBindTexture(GL_TEXTURE_2D, 0);
    //glBindRenderbuffer(GL_RENDERBUFFER, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
    assert (glGetError () == GL_NO_ERROR);
}

2. Потом загружаю модель которая должна отобразиться на экране. Она использует свой шейдер и свою текстуру:

{
    glGenTextures (1, &texture);
    glBindTexture (GL_TEXTURE_2D, texture);
    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_MIN_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
    if (_current_data)
        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, _current_data);
 
    glBindTexture (GL_TEXTURE_2D, 0);
    assert (glGetError () == GL_NO_ERROR);
}

3. Затем в функцию рендеринга:

{
    glBindFramebuffer(GL_FRAMEBUFFER, fbo.object);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport (0, 0, 1080, 1920);
 
    model->render(fbo, camera);
 
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
        
    glViewport(0, 0, 1080, 1920);
 
    glUseProgram(shaderProgram);
 
    glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices);
    glEnableVertexAttribArray(vertexLocation);
    glVertexAttribPointer(textureCordLocation, 2, GL_FLOAT, GL_FALSE, 0, quadTextureCords);
    glEnableVertexAttribArray(textureCordLocation);
 
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, fbo.texture_map);
    glUniform1i(textureLocation, 0);
 
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}

4. Функция render у созданной model:

{
    glUseProgram (shader->program);
        
    // bind texture
    glActiveTexture (GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, texture->texture);
    glUniform1i (shader->Uniform ("texture"), 0);
        
    // set uniforms
    glUniformMatrix4fv (shader->Uniform ("camera_projection"), 1, false, &camera.projection[0][0]);
    glUniformMatrix4fv (shader->Uniform ("camera_transformation"), 1, false, &camera.transformation[0][0]);
        
    glBindBuffer (GL_ARRAY_BUFFER, vertices);
    glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, indices);
        
    // set attributes
    GLint position = shader->Location ("position");
    assert (position >= 0);
    glVertexAttribPointer (position, 4, GL_FLOAT, GL_FALSE, sizeof (Mesh::Vertex), 0);
    glEnableVertexAttribArray (position);
        
    GLint uv = shader->Location ("uv");
    if (node.uvs != 0 && uv >= 0) {
        glVertexAttribPointer (uv, 2, GL_FLOAT, GL_FALSE, sizeof (Mesh::Vertex), (GLvoid*) (sizeof (GLfloat) * 4));
        glEnableVertexAttribArray (uv);
    }
        
    GLint normal = shader->Location ("normal");
    if (node.normals != 0 && normal >= 0) {
        glVertexAttribPointer (normal, 4, GL_FLOAT, GL_FALSE, sizeof (Mesh::Vertex), (GLvoid*) (sizeof (GLfloat) * 4 + sizeof (GLfloat) * 2));
        glEnableVertexAttribArray (normal);
    }
        
    GLint color = shader->Uniform ("color");
    if (color >= 0) {
        glUniform4f (color, this->color[0], this->color[1], this->color[2], this->color[3]);
    }
        
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
    // render to framebuffer
    glDrawElements (GL_TRIANGLES, node.faces * 3, GL_UNSIGNED_INT, 0);
        
    glDisable (GL_BLEND);
 
    // reset state
    if (normal >= 0) {
        glDisableVertexAttribArray (normal);
    }
    if (uv >= 0) {
        glDisableVertexAttribArray (uv);
    }
    glDisableVertexAttribArray (position);
        
    glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer (GL_ARRAY_BUFFER, 0);
         
    // checks errors
    assert (glGetError ()== GL_NO_ERROR);
  
    // reset state
    glBindTexture (texture->target, 0);
        
    glUseProgram (0);
}

В итоге получаю только черный экран.

Суть в том, что таких model несколько, и у меня идея (возможно неверная, поправьте если так) срендерить все эти модели в FBO, и потом поместить FXAA фильтр в fragment.glsl, который выведет на экран текстуру, привязанную к FBO

Подскажите, что я делаю не так?)

Попробуйте отключить проверку буфера глубины (или же очистить его) перед выводом текстуры на экран:

glDisable(GL_DEPTH_TEST);
// glEnable(GL_DEPTH_TEST) перед выводом 3D геометрии

или

glClear(GL_DEPTH_BUFFER_BIT);
или
glDepthFunc(GL_ALWAYS);
// glDepthFunc(GL_LESS) перед выводом 3D геометрии

goto-vlad
()
Ответ на: комментарий от goto-vlad

И вообще, я тут наколхозил небольшой тест для проверки моих предположений выше. Может будет вам полезен:

#include <stdio.h>
#include <assert.h>

#include <GLES2/gl2.h>
#include <GLFW/glfw3.h>

#define WIDTH  1280
#define HEIGHT  720

#define SHADER(x) "#version 100\n"#x

static const char *vsMain =
SHADER(
attribute vec2 pos;
void main()
{
	gl_Position = vec4(pos, 0.0, 1.0);
});

static const char *fsMain =
SHADER(
void main()
{
	gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
});

static const char *vsScreen =
SHADER(
attribute vec2 pos;
varying   vec2 uv;
void main()
{
	gl_Position = vec4(pos, 0.0, 1.0);
	uv = pos * vec2(0.5) + vec2(0.5);
});

static const char *fsScreen =
SHADER(
precision mediump float;
varying vec2 uv;
uniform sampler2D tex;
void main()
{
	gl_FragColor = texture2D(tex, uv);
});

static GLuint program;
static GLuint screenProgram;

static GLuint framebuffer;
static GLuint zbuf;
static GLuint fbTex;

static const GLuint ATTRIB_POS = 0;

static GLint UNIFORM_TEX;

typedef struct Attrib Attrib;
struct Attrib
{
	const char *name;
	GLuint      loc;
};

static GLuint InitProgram(const char *vsStr, const char *fsStr, const Attrib *attribs)
{
	GLuint vs, fs;
	GLuint prog;

	vs = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vs, 1, &vsStr, NULL);
	glCompileShader(vs);

	fs = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fs, 1, &fsStr, NULL);
	glCompileShader(fs);

	prog = glCreateProgram();
	glAttachShader(prog, vs);
	glAttachShader(prog, fs);

	while (attribs->name != NULL)
	{
		glBindAttribLocation(prog, attribs->loc, attribs->name);
		++attribs;
	}
	glLinkProgram(prog);

	glDetachShader(prog, vs);
	glDetachShader(prog, fs);
	glDeleteShader(vs);
	glDeleteShader(fs);

	return prog;
}

static void Initialize(void)
{
	glEnable(GL_DEPTH_TEST);

	program = InitProgram(vsMain, fsMain, (Attrib[]){{"pos", ATTRIB_POS}, {0}});

	screenProgram = InitProgram(vsScreen, fsScreen, (Attrib[]){{"pos", ATTRIB_POS}, {0}});
	UNIFORM_TEX   = glGetUniformLocation(screenProgram, "tex");

	glGenFramebuffers (1, &framebuffer);
	glGenTextures     (1, &fbTex);
	glGenRenderbuffers(1, &zbuf);

	glBindFramebuffer (GL_FRAMEBUFFER,  framebuffer);
	glActiveTexture   (GL_TEXTURE0);
	glBindTexture     (GL_TEXTURE_2D,   fbTex);
	glBindRenderbuffer(GL_RENDERBUFFER, zbuf);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    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_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, WIDTH, HEIGHT);

	glFramebufferTexture2D   (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,   fbTex, 0);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_RENDERBUFFER, zbuf);

	assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}

static void Render(void)
{
	const float verts[6] =
	{
		-0.5f, -0.5f,
		 0.5f, -0.5f,
		 0.0f,  0.5f
	};

	glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
	glViewport(0, 0, WIDTH, HEIGHT);
	glDepthFunc(GL_LESS);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glUseProgram(program);

	glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, verts);
	glEnableVertexAttribArray(ATTRIB_POS);
	glDrawArrays(GL_TRIANGLES, 0, 3);

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glViewport(0, 0, WIDTH, HEIGHT);

	glDepthFunc(GL_ALWAYS);
	//glDisable(GL_DEPTH_TEST);
	//glClear(GL_DEPTH_BUFFER_BIT);

	glUseProgram(screenProgram);

	const float fullScreenVerts[6] =
	{
		-1.0f, -1.0f,
		 3.0f, -1.0f,
		-1.0f,  3.0f
	};
	glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, fullScreenVerts);
    glEnableVertexAttribArray(ATTRIB_POS);

	glUniform1i(UNIFORM_TEX, 0);

	glDrawArrays(GL_TRIANGLES, 0, 3);
}


int main(void)
{
	GLFWwindow* win;

	if (!glfwInit())
	{
		return 1;
	}

    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);

    win = glfwCreateWindow(WIDTH, HEIGHT, "test", NULL, NULL);
    if (!win)
    {
        glfwTerminate();
		return 1;
    }

	glfwMakeContextCurrent(win);

	Initialize();
	while (!glfwWindowShouldClose(win))
	{
		if (glfwGetKey(win, GLFW_KEY_ESCAPE)) break;

		Render();
	
		glfwSwapBuffers(win);
		glfwPollEvents();
	}

	glfwDestroyWindow(win);
	glfwTerminate();
	return 0;
}
Небольшая оптимизация - вместо двух треугольников занимающих весь экран можно выводить один с координатами (-1, -1), (3, -1) и (-1, 3), тем самым мы избавляем себя от необходимости использовать индексный буфер, а также можем высчитывать текстурные координаты на лету прямо в шейдере - минус еще один буфер.

goto-vlad
()

array of array textures

anonymous
()

OpenGL не нужен

Тебе нужны два рендер таргета: промежуточный и экранный. Рендеришь всё в первый, потом аттачишь его как текстуру к FXAA шейдеру и ставишь ртшкой свой фреимбуфер.

// Код не читал, от OGL плакать хочется

Stil ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.