我正在写一个程序,可以合成两个图像通过着色器和保存结果本地。简单地输出到视口会减少屏幕外的像素,我想让它成为无窗口的,所以我尝试使用Frameebuffer对象进行屏幕外渲染。
我试着编写原型项目来理解FBO并在屏幕上显示单个纹理,但结果只是一个空白的背景彩色视口,就像这样:
。有趣的是,如果我改变颜色值,背景颜色会在碎片着色器中得到正确的着色,但是帧缓冲区中的任何类型的纹理都是不可见的,或者根本不会传递到着色器。
下面是我代码:
main.cpp
const char* img1_path = "C:/..path../img_00001.jpg";
const char* img2_path = "C:/..path../img_00002.jpg";
GLfloat square_vertices[] =
{ // COORDINATES / COLORS / TexCoord //
-1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Lower left corner
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Upper left corner
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Upper right corner
1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f // Lower right corner
};
GLuint square_indices[] =
{
0, 2, 1, // Upper triangle
0, 3, 2 // Lower triangle
};
// for FBO
static const GLfloat g_quad_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#ifdef __cplusplus
}
#endif
#define WIDTH 1280
#define HEIGHT 720
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // usiamo il core profile
// create glfwwindow
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "test", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
gladLoadGL();
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
// VAO init
GLuint VAO1;
glGenVertexArrays(1, &VAO1);
glBindVertexArray(VAO1);
// my custom texture (1920x1080)
int widthImg, heightImg, numColCh;
stbi_set_flip_vertically_on_load(true);
unsigned char* bytes = stbi_load(img1_path, &widthImg, &heightImg, &numColCh, 0);
// shader reading, compiling and linking
Shader shaderProgram(vert_path, frag_path);
// Texture setup
GLuint Texture;
glGenTextures(1, &Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, bytes);
// shader uniform linking
GLuint TextureID = glGetUniformLocation(shaderProgram.ID, "tex0");
// VBO
GLuint VBO1;
glGenBuffers(1, &VBO1);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
glBufferData(GL_ARRAY_BUFFER, sizeof(square_vertices), square_vertices, GL_STATIC_DRAW);
// EBO
GLuint EBO1;
glGenBuffers(1, &EBO1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO1);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(square_indices), square_indices, GL_STATIC_DRAW);
// FBO
// framebuffer
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_RGB, WIDTH, HEIGHT, 0, GL_RGB, 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);
// depth buffer
GLuint depthrenderbuffer;
glGenRenderbuffers(1, &depthrenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, WIDTH, HEIGHT);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
// Set list of draw buffers.
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers);
// Error checking framebuffer
auto fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Framebuffer error: " << fboStatus << std::endl;
// FBO vertices
GLuint quad_vertexbuffer;
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
// Create and compile our GLSL program from the shaders
Shader quad_program(FB_vert, FB_frag);
GLuint texID = glGetUniformLocation(quad_program.ID, "FBtex");
// LOOP
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && !glfwWindowShouldClose(window)) {
// Render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glViewport(0, 0, WIDTH, HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// non-FBO shader
glUseProgram(shaderProgram.ID);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
glUniform1i(TextureID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// bind EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO1);
// drawelements
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
// Render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, WIDTH, HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// FBO shader
glUseProgram(quad_program.ID);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glGenerateMipmap(GL_TEXTURE_2D);
glUniform1i(texID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangles
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteBuffers(1, &VAO1);
glDeleteBuffers(1, &VBO1);
glDeleteBuffers(1, &EBO1);
shaderProgram.Delete();
quad_program.Delete();
glDeleteFramebuffers(1, &FramebufferName);
glDeleteTextures(1, &renderedTexture);
glDeleteRenderbuffers(1, &depthrenderbuffer);
glDeleteBuffers(1, &quad_vertexbuffer);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
字符集
FBO.vert(通过)
#version 460 core
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inTexCoords;
out vec2 texCoords;
void main()
{
gl_Position = vec4(inPos.x, inPos.y, 0.0, 1.0);
texCoords = inTexCoords;
}
型
FBO.frag
#version 460 core
in vec2 texCoords;
out vec3 color;
uniform sampler2D FBtex;
void main()
{
vec3 temp = texture(FBtex, texCoords).xyz;
color = temp;
// this works and shades the blue background color
//color = vec3(temp.x + 0.3f, temp.y + 0.3f, temp.z + 0.3f);
}
型
我被难倒了,我最近才学会opengl,还有很多东西让我困惑,我不知道如何导航,例如函数的顺序和内部状态机,所以如果你能回答,请尽可能详尽和简单。我遵循了许多FBO教程,其中许多都有非常相似的代码,但纹理只是不会显示在屏幕上。
奖金问题:
即使我只需要纹理,使用帧缓冲区是否需要深度缓冲区?如果是,相机+ 3D模型的实现是否也需要?
glFramebufferTexture2D()代替glFramebufferTexture()会有帮助吗?
1条答案
按热度按时间wztqucjr1#
您需要渲染Texture而不是RenderedTexture。您还需要添加TextParameters。然后可以将纹理渲染为四边形,然后可以使用glFramebufferTexture在帧缓冲区渲染纹理,最后再次将纹理渲染为四边形。
深度缓冲区和摄影机模型不是必需的,可以使用glFramebufferTexture或glFramebufferTexture2D。
字符集