英文:
OpenGL render-to-texture-via-FBO -- incorrect display vs. normal Texture
问题
离屏渲染到绑定纹理的离屏帧缓冲对象应该是非常简单的,但是我遇到了一个我无法理解的问题。
我的完整示例程序(目前只支持2D!)在这里:
以下是一些描述。
我创建了一个512x512的rgba纹理对象,将其绑定到一个FBO。此时不需要深度或其他渲染缓冲区,严格为2D。
以下是非常简单的着色器渲染到这个纹理:
顶点着色器:
varying vec2 vPos; attribute vec2 aPos;
void main (void) {
vPos = (aPos + 1) / 2;
gl_Position = vec4(aPos, 0.0, 1.0);
}
在aPos中,只是获取一个包含四个四边形的xy坐标的VBO(-1,-1 :: 1,-1 :: 1,1 :: -1,1)
因此,尽管帧缓冲区的分辨率理论上应该是512x512,但着色器将其“纹理”渲染到“全屏(离屏)四边形”,遵循GL的-1..1坐标范例。
片段着色器:
varying vec2 vPos;
void main (void) {
gl_FragColor = vec4(0.25, vPos, 1);
}
因此,它设置了一个完全不透明的颜色,红色固定为0.25,绿色/蓝色取决于x/y在0和1之间的任何位置。
此时,我的假设是,渲染一个512x512的纹理,仅显示-1..1的全屏(离屏)四边形,从0..1的绿色/蓝色片段着色。
所以这是我的离屏设置。在屏幕上,我有另一个真正可见的全屏四边形,具有4个xyz坐标{ -1,-1,1 ::: 1,-1,1 ::: 1,1,1 ::: -1,1,1 }。同样,现在只支持2D,所以没有矩阵,因此z始终为1。
这个四边形由不同的着色器绘制,简单地渲染给定的纹理,类似于教科书上的GL-101风格。在我上面链接的示例程序中,我有一个简单的布尔切换doRtt,当这个值为false(默认值)时,根本不执行渲染到纹理的操作,这个着色器只是显示当前目录中的texture.jpg。
这种doRtt=false模式显示了第二个屏幕上的四边形渲染器对于我的当前要求是“正确的”,并且按照我想要的方式进行纹理化:在垂直和水平方向上重复两次(稍后将被夹住,重复只是为了测试),否则缩放时没有纹理过滤或mipmap。
因此,无论窗口(因此视口)如何调整大小,我们始终看到一个全屏四边形,其中一个纹理在水平方向上重复两次,垂直方向上重复两次。
现在,当doRtt=true时,第二个着色器仍然完成其工作,但纹理从未完全正确缩放 - 或者绘制,这一点我不确定,因为不幸的是我们不能只是说“嘿,gl将这个FBO保存到磁盘上进行调试”。
RTT着色器确实执行了一些部分渲染(或者可能是完全渲染,再次无法确定离屏发生了什么...)特别是当您将视口调整得比默认大小小得多时,您会看到纹理重复之间的断裂,并且并未显示我们非常简单的RTT片段着色器中预期的所有颜色。
(A)要么:512x512的纹理由我的代码正确创建,但没有正确映射(但是为什么doRtt=false时,任何给定的texture.jpg文件使用完全相同的简单纹理化四边形着色器都可以正常显示?)
(B)要么:512x512的纹理没有正确渲染,而且rtt片段着色器根据窗口分辨率改变其输出 - 但为什么?离屏四边形始终为-1..1的x和y,顶点着色器始终将其映射到片段坐标0..1,RTT纹理对于这个简单的测试始终保持在512x512!
请注意,离屏四边形和屏幕上的四边形坐标都不会改变,始终是“全屏”(两个维度都是-1..1)。
再次强调,这应该是非常简单的。我到底漏掉了什么?
英文:
off-screen rendering to a texture-bound offscreen framebuffer object should be so trivial but I'm having a problem I cannot wrap my head around.
My full sample program (2D only for now!) is here:
See below for some descriptions.
I'm creating an rgba texture object 512x512, bind it to an FBO. No depth or other render buffers are needed at this point, strictly 2D.
The following extremely simple shaders render to this texture:
Vertex shader:
varying vec2 vPos; attribute vec2 aPos;
void main (void) {
vPos = (aPos + 1) / 2;
gl_Position = vec4(aPos, 0.0, 1.0);
}
In aPos this just gets a VBO containing 4 xy coords for a quad (-1, -1 :: 1, -1 :: 1, 1 :: -1, 1)
So although the framebuffer resolution should theoretically by 512x512 obviously the shader renders its "texture" onto a "full-(off)screen quad", following GLs -1..1 coords paradigm.
Fragment shader:
varying vec2 vPos;
void main (void) {
gl_FragColor = vec4(0.25, vPos, 1);
}
So it sets a fully opaque color with red fixed at 0.25 and green/blue depending on x/y anywhere between 0 and 1.
At this point my assumption is that a 512x512 texture is rendered showing only the -1..1 full-(off)screen quad, fragment-shaded for green/blue from 0..1.
So this is my off-screen setup. On-screen, I have another real visible full-screen quad with 4 xyz coords { -1, -1, 1 ::: 1, -1, 1 ::: 1, 1, 1 ::: -1, 1, 1 }. Again, for now this is 2D so no matrices and so z is always 1.
This quad is drawn by a different shader, simply rendering a given texture, text-book GL-101 style. In my sample program linked above I have a simple boolean toggle doRtt, when this is false (the default), render-to-texture is not performed at all and this shader simply shows uses texture.jpg from the current directory.
This doRtt=false mode shows that the second on-screen quad-renderer is "correct" for my current requirements and performs the texturing as I want it to: repeated twice vertically and twice horizontally (later will be clamped, repeat is just for testing here), otherwise scaling with NO texture filtering or mipmapping.
So no matter how the window (and thus view port) is resized, we always see a full-screen quad with a single texture repeated twice horizontally, twice vertically.
Now, with doRtt=true, the second shader still does its job but the texture is never fully correctly scaled -- or drawn, this I'm not sure since unfortunately we can't just say "hey gl save this FBO to disk for debugging purposes".
The RTT shader DOES perform some partial rendering (or maybe a full one, again can't be sure what's happening off-screen...) Especially when you resize the viewport a lot smaller than the default size you see the breaks between the texture repeats, and not all colors to be expected from our very simple RTT fragment shader are indeed shown.
(A) either: the 512x512 texture is created correctly but not mapped correctly by my code (but then why is with doRtt=false any given texture.jpg file using the exact same simple textured-quad-shader showing just fine?)
(B) or: the 512x512 texture is not rendered correctly and somehow the rtt frag shader changes its output depending on the window resolution -- but why? The off-screen quad is always at -1..1 for x and y, the vertex shader always maps this to fragment coords 0..1, the RTT texture always stays at 512x512 for this simple test!
Note, BOTH the off-screen quad AND the on-screen quad never change their coords and are always "full-screen" (-1..1 in both dimensions).
Again, this should be so simple. What on earth am I missing?
Specs: OpenGL 4.2 (but the code doesn't need any 4.2 features obviously!), Nvidia Quadro 5010M, openSuse 12.1 64bit, Golang Weekly 22-Feb-2012.
答案1
得分: 12
首先 - 尝试检查OpenGL错误。在每个OpenGL函数之后调用glGetError()。此外,您必须设置正确的视口进行绘制。在绘制到FBO之前调用glViewport(0, 0, 512, 512)。在绘制到屏幕之前调用glViewport(0, 0, display_width, display_height)。
此外,在使用FBO渲染到rttFrameTex时,不需要绑定rttFrameTex。只有在着色器中读取纹理时才需要绑定纹理。
英文:
First of all - try checking OpenGL errors. Call glGetError() after each OpenGL function. Also you must set correct viewport for drawing. Before drawing to FBO call glViewport(0, 0, 512, 512). Before drawing to screen call glViewport(0, 0, display_width, display_height).
Also there is no need to bind rttFrameTex when you are rendering to it using FBO. Binding texture is needed only when you are reading texture in shader.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论