渲染到 FBO,采样失败
Render to FBO, sampling fails
我正在尝试渲染到 FBO,然后在 OpenGL/LWJGL 中进行屏幕显示,但我得到了奇怪的结果。
我的场景如果直接渲染到帧缓冲区就可以正常工作,看起来像这样:
但是当我渲染到 FBO,然后渲染到默认帧缓冲区上的四边形时,我得到了这个:
看起来图像中的所有颜色都以一种颜色进行了平均化处理,就好像用这种颜色清除了屏幕一样。
我的猜测是,四边形上的纹理采样有问题,但我无法弄清楚。
当我用 glPolymode 看到边缘时,四边形显然在那里 - GL_LINE。此外,当我移动游戏中的相机时,四边形上的单一颜色会发生变化,并且不知何故也会反映出屏幕上最突出的颜色。那么也许您可以指出可能显而易见的解决方案?我将在本文末尾放置一些我认为相关的代码 post。
这就是我设置小队顶点和 uv 坐标的方式。我对多维数据集使用相同的方法和父 类,所以我知道这是可行的:
vertices[0] = new Vertex(-1.0f,-1.0f,0.0f);
vertices[0].setTexCoords(0.0f,0.0f);
vertices[1] = new Vertex(-1.0f,1.0f,0.0f);
vertices[1].setTexCoords(0.0f,1.0f);
vertices[2] = new Vertex(1.0f,1.0f,0.0f);
vertices[2].setTexCoords(1.0f,1.0f);
vertices[3] = new Vertex(1.0f,-1.0f,0.0f);
vertices[3].setTexCoords(1.0f,0.0f);
这就是我将它们绑定到 vbos 的方式:
vaoID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoID);
//POSITION - LOCATION 0
int vboID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
FloatBuffer buffer = BufferUtils.createFloatBuffer(vertices.length*3);
buffer.put(getPositions());
buffer.flip();
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
buffer.clear();
//... some code for color and normal, going into VBO location 1 and 2
//TEX COORDS - LOCATION 3
vboID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
buffer = BufferUtils.createFloatBuffer(vertices.length*2);
buffer.put(getTexCoords());
buffer.flip();
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(3, 2, GL11.GL_FLOAT, false, 0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
buffer.clear();
这就是我在着色器中为四边形绑定属性位置的方式:
protected void bindAttributes(){
GL20.glBindAttribLocation(id, 0, "vertex_position");
GL20.glBindAttribLocation(id, 3, "vertex_texCoord");
}
这就是我渲染屏幕四边形的方式:
GL20.glUseProgram(presentShader.getProgramID());
GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(3);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
//GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
GL11.glDrawElements(GL11.GL_TRIANGLES, screenQuad.getMesh(0).getIndexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(3);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
GL20.glUseProgram(0);
这是我的顶点和片段着色器:
顶点:
#version 400 core
in vec2 vertex_position;
in vec2 vertex_texCoords;
out vec2 pass_texCoords;
void main(){
gl_Position = vec4(vertex_position.x, vertex_position.y, 0.0f, 1.0f);
pass_texCoords = vertex_texCoords;
}
片段:
#version 400 core
in vec2 pass_texCoords;
out vec4 fragment_color;
uniform sampler2D screenTexture;
void main(){
fragment_color = texture(screenTexture, pass_texCoords);
//fragment_color = vec4(0.3,0.3,0.3,1.0);
}
最后,这是我的渲染过程:
准备();
绘制场景();
目前();
具有这些功能:
public void prepare(){
//FBO aktivieren, alles danach wird auf FBO-Textur gerendert
GL11.glClearColor(0.0f,0.0f,0.0f, 1.0f);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_STENCIL_TEST);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
}
public void present(){
//Standard Framebuffer aktivieren
GL11.glClearColor(1.0f,1.0f,1.0f, 1.0f);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDisable(GL11.GL_STENCIL_TEST);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL20.glUseProgram(presentShader.getProgramID());
GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(3);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
GL11.glDrawElements(GL11.GL_TRIANGLES, screenQuad.getMesh(0).getIndexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(3);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
GL20.glUseProgram(0);
}
编辑:也许我应该添加我如何设置 FBO:
private void linitializeFrameBuffer(int viewportWidth, int viewportHeight){
//COLOR TEXTURE
frameBufferID = GL30.glGenFramebuffers();
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID); // GL_READ_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER
frameBufferTextureID = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID); //GL_TEXTURE_1D, GL_TEXTURE2D, GL_TEXTURE3D
FloatBuffer pixelBuffer;
pixelBuffer = BufferUtils.createFloatBuffer(viewportWidth*viewportHeight*3);
pixelBuffer.clear();
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, viewportWidth, viewportHeight, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) null);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR );
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR );
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
//Attach the new Texture to the framebuffer
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, frameBufferTextureID, 0);
//DEPTH BUFFER
depthBufferID = GL30.glGenRenderbuffers();
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBufferID);
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, viewportWidth, viewportHeight);
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, 0);
//Attach the new renderbuffer to the framebuffer
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depthBufferID);
if(GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER) != GL30.GL_FRAMEBUFFER_COMPLETE){
System.out.println("ERROR::FRAMEBUFFER:: Framebuffer is not complete!");
}
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
}
首先,
GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(3);
enableVertexAttribArray 应该在初始化 VAO 的函数中,而不是在渲染循环中 ;)。那样的话,disableVertexAttribArray 是 "useless".
其次,我不太方便使用 "binding to work",因为直接状态访问是 OpenGL 核心的一部分。
但是,我可以看到 2 个最终警告(即使我不太确定)
您将 "internal format" GL_RGB 赋给 glTexImage2D,如果我是您,我会使用 GL_RGB8。 (我知道 GL_RGB 使用 glTexStorage 是不正确的,但也许可以将它与 GLTexImage2D 一起使用,启用 arb 调试输出以了解是否存在错误)。
在将纹理发送到 frameBuffer 之前解除绑定(阅读文档后,应该没问题)。
您正在创建从未使用过的 "pixelBuffer"。
最后,我在使用 Depth 和 Stencil 缓冲区时遇到了很多问题,尤其是在使用 renderBuffer 时。
我建议您切换到纹理而不是 renderBuffer 并开始 "debug" 您的程序只使用没有模板的 depthTexture。
编辑:正如 Djindjidj 所写,您在着色器中不遵守 vec2 / vec3
得到解决方案。
着色器中的纹理坐标称为in vec2 vertex_texCoords;
我将它们引用为 GL20.glBindAttribLocation(id, 3, "vertex_texCoord");
将其更改为 GL20.glBindAttribLocation(id, 3, "vertex_texCoords");
即可。
我正在尝试渲染到 FBO,然后在 OpenGL/LWJGL 中进行屏幕显示,但我得到了奇怪的结果。
我的场景如果直接渲染到帧缓冲区就可以正常工作,看起来像这样:
但是当我渲染到 FBO,然后渲染到默认帧缓冲区上的四边形时,我得到了这个:
看起来图像中的所有颜色都以一种颜色进行了平均化处理,就好像用这种颜色清除了屏幕一样。
我的猜测是,四边形上的纹理采样有问题,但我无法弄清楚。
当我用 glPolymode 看到边缘时,四边形显然在那里 - GL_LINE。此外,当我移动游戏中的相机时,四边形上的单一颜色会发生变化,并且不知何故也会反映出屏幕上最突出的颜色。那么也许您可以指出可能显而易见的解决方案?我将在本文末尾放置一些我认为相关的代码 post。
这就是我设置小队顶点和 uv 坐标的方式。我对多维数据集使用相同的方法和父 类,所以我知道这是可行的:
vertices[0] = new Vertex(-1.0f,-1.0f,0.0f);
vertices[0].setTexCoords(0.0f,0.0f);
vertices[1] = new Vertex(-1.0f,1.0f,0.0f);
vertices[1].setTexCoords(0.0f,1.0f);
vertices[2] = new Vertex(1.0f,1.0f,0.0f);
vertices[2].setTexCoords(1.0f,1.0f);
vertices[3] = new Vertex(1.0f,-1.0f,0.0f);
vertices[3].setTexCoords(1.0f,0.0f);
这就是我将它们绑定到 vbos 的方式:
vaoID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoID);
//POSITION - LOCATION 0
int vboID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
FloatBuffer buffer = BufferUtils.createFloatBuffer(vertices.length*3);
buffer.put(getPositions());
buffer.flip();
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
buffer.clear();
//... some code for color and normal, going into VBO location 1 and 2
//TEX COORDS - LOCATION 3
vboID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
buffer = BufferUtils.createFloatBuffer(vertices.length*2);
buffer.put(getTexCoords());
buffer.flip();
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(3, 2, GL11.GL_FLOAT, false, 0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
buffer.clear();
这就是我在着色器中为四边形绑定属性位置的方式:
protected void bindAttributes(){
GL20.glBindAttribLocation(id, 0, "vertex_position");
GL20.glBindAttribLocation(id, 3, "vertex_texCoord");
}
这就是我渲染屏幕四边形的方式:
GL20.glUseProgram(presentShader.getProgramID());
GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(3);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
//GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
GL11.glDrawElements(GL11.GL_TRIANGLES, screenQuad.getMesh(0).getIndexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(3);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
GL20.glUseProgram(0);
这是我的顶点和片段着色器: 顶点:
#version 400 core
in vec2 vertex_position;
in vec2 vertex_texCoords;
out vec2 pass_texCoords;
void main(){
gl_Position = vec4(vertex_position.x, vertex_position.y, 0.0f, 1.0f);
pass_texCoords = vertex_texCoords;
}
片段:
#version 400 core
in vec2 pass_texCoords;
out vec4 fragment_color;
uniform sampler2D screenTexture;
void main(){
fragment_color = texture(screenTexture, pass_texCoords);
//fragment_color = vec4(0.3,0.3,0.3,1.0);
}
最后,这是我的渲染过程: 准备(); 绘制场景(); 目前();
具有这些功能:
public void prepare(){
//FBO aktivieren, alles danach wird auf FBO-Textur gerendert
GL11.glClearColor(0.0f,0.0f,0.0f, 1.0f);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_STENCIL_TEST);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
}
public void present(){
//Standard Framebuffer aktivieren
GL11.glClearColor(1.0f,1.0f,1.0f, 1.0f);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDisable(GL11.GL_STENCIL_TEST);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL20.glUseProgram(presentShader.getProgramID());
GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(3);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
GL11.glDrawElements(GL11.GL_TRIANGLES, screenQuad.getMesh(0).getIndexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(3);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
GL20.glUseProgram(0);
}
编辑:也许我应该添加我如何设置 FBO:
private void linitializeFrameBuffer(int viewportWidth, int viewportHeight){
//COLOR TEXTURE
frameBufferID = GL30.glGenFramebuffers();
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID); // GL_READ_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER
frameBufferTextureID = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID); //GL_TEXTURE_1D, GL_TEXTURE2D, GL_TEXTURE3D
FloatBuffer pixelBuffer;
pixelBuffer = BufferUtils.createFloatBuffer(viewportWidth*viewportHeight*3);
pixelBuffer.clear();
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, viewportWidth, viewportHeight, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) null);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR );
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR );
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
//Attach the new Texture to the framebuffer
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, frameBufferTextureID, 0);
//DEPTH BUFFER
depthBufferID = GL30.glGenRenderbuffers();
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBufferID);
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, viewportWidth, viewportHeight);
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, 0);
//Attach the new renderbuffer to the framebuffer
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depthBufferID);
if(GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER) != GL30.GL_FRAMEBUFFER_COMPLETE){
System.out.println("ERROR::FRAMEBUFFER:: Framebuffer is not complete!");
}
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
}
首先,
GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(3);
enableVertexAttribArray 应该在初始化 VAO 的函数中,而不是在渲染循环中 ;)。那样的话,disableVertexAttribArray 是 "useless".
其次,我不太方便使用 "binding to work",因为直接状态访问是 OpenGL 核心的一部分。 但是,我可以看到 2 个最终警告(即使我不太确定)
您将 "internal format" GL_RGB 赋给 glTexImage2D,如果我是您,我会使用 GL_RGB8。 (我知道 GL_RGB 使用 glTexStorage 是不正确的,但也许可以将它与 GLTexImage2D 一起使用,启用 arb 调试输出以了解是否存在错误)。
在将纹理发送到 frameBuffer 之前解除绑定(阅读文档后,应该没问题)。
您正在创建从未使用过的 "pixelBuffer"。
最后,我在使用 Depth 和 Stencil 缓冲区时遇到了很多问题,尤其是在使用 renderBuffer 时。 我建议您切换到纹理而不是 renderBuffer 并开始 "debug" 您的程序只使用没有模板的 depthTexture。
编辑:正如 Djindjidj 所写,您在着色器中不遵守 vec2 / vec3
得到解决方案。
着色器中的纹理坐标称为in vec2 vertex_texCoords;
我将它们引用为 GL20.glBindAttribLocation(id, 3, "vertex_texCoord");
将其更改为 GL20.glBindAttribLocation(id, 3, "vertex_texCoords");
即可。