尝试实现渲染到纹理
我在使用 OpenGL 3 实现纹理渲染时遇到问题。
我的问题是,渲染到帧缓冲区后,渲染的对象似乎变形了,这可能意味着某处发生了错误的转换。这是没有意义的,因为当不使用我的帧缓冲区时,对象渲染得很好(请参见帖子底部)。
当前结果是这样的:
当前结果http://k.minus.com /jZVgUuLYRtapv.jpg
预期结果是这样的(或类似的结果,这刚刚经过 GIMP 处理): 预期 http://k.minus.com/jA5rLM8lmXQYL.jpg
因此这意味着我'我在帧缓冲区设置代码或其他地方做错了什么。但我看不到什么。
FBO是通过以下函数设置的:
unsigned int fbo_id;
unsigned int depth_buffer;
int m_FBOWidth, m_FBOHeight;
unsigned int m_TextureID;
void initFBO() {
m_FBOWidth = screen_width;
m_FBOHeight = screen_height;
glGenRenderbuffers(1, &depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_FBOWidth, m_FBOHeight);
glGenTextures(1, &m_TextureID);
glBindTexture(GL_TEXTURE_2D, m_TextureID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_FBOWidth, m_FBOHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo_id);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_TextureID, 0);
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
这是我的绘图框代码,它只需要一个变换矩阵并调用适当的函数。 P 的当前值是投影矩阵和视图矩阵 (V) 的单位矩阵。
void drawBox(const Matrix4& M) {
const Matrix4 MVP = M * V * P;
if (boundshader) {
glUniformMatrix4fv((*boundshader)("MVP"), 1, GL_FALSE, &MVP[0]);
}
glBindVertexArray(vaoID);
glDrawElements(GL_TRIANGLES, sizeof(cube.polygon)/sizeof(cube.polygon[0]), GL_UNSIGNED_INT, 0);
}
void drawStaticBox() {
Matrix4 M(1);
translate(M, Vector3(0,0,-50));
drawBox(M);
}
void drawRotatingBox() {
Matrix4 M(1);
rotate(M, rotation(Vector3(1, 0, 0), rotation_x));
rotate(M, rotation(Vector3(0, 1, 0), rotation_y));
rotate(M, rotation(Vector3(0, 0, 1), rotation_z));
translate(M, Vector3(0,0,-50));
drawBox(M);
}
以及GLUT调用的显示函数。
void OnRender() {
/////////////////////////////////////////
// Render to FBO
glClearColor(0, 0, 0.2f,0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
glViewport(0, 0, m_FBOWidth, m_FBOHeight);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
GL_CHECK_ERRORS
colorshader.Use();
boundshader = &colorshader;
drawRotatingBox();
colorshader.UnUse();
/////////////////////////////////////////
// Render to Window
glClearColor(0, 0, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, screen_width, screen_height);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
GL_CHECK_ERRORS
texshader.Use();
boundshader = &texshader;
glBindTexture(GL_TEXTURE_2D, m_TextureID);
drawStaticBox();
texshader.UnUse();
// Swap le buffers
glutSwapBuffers();
}
并且...强制性纹理着色器代码
顶点
#version 330
in vec2 vUV;
in vec3 vVertex;
smooth out vec2 vTexCoord;
uniform mat4 MVP;
void main()
{
vTexCoord = vUV;
gl_Position = MVP*vec4(vVertex,1);
}
片段
#version 330
smooth in vec2 vTexCoord;
out vec4 vFragColor;
uniform sampler2D textureMap;
void main(void)
{
vFragColor = texture(textureMap, vTexCoord);
}
以下是不使用FBO逻辑时渲染的内容: 呈现给 FBO http://k.minus.com/jiP7kTOSLLvHk.jpg 的内容
。 .. 帮助?
关于我可能做错了什么有什么想法吗? 可根据要求提供更多来源。
I'm having trouble implementing render to texture with OpenGL 3.
My issue is that after rendering to the frame buffer, it appears the rendered object becomes deformed, which may imply a bad transformation has occurred somewhere. Which doesn't make sense as the object renders fine when not using my frame buffer (see bottom of post).
The current result is such:
Current result http://k.minus.com/jZVgUuLYRtapv.jpg
And the expected result was this (or something similar, this has just been GIMP'd):
Expected http://k.minus.com/jA5rLM8lmXQYL.jpg
It therefore implies that I'm doing something wrong in my frame buffer set up code, or elsewhere. But I can't see what.
The FBO is set up through the following function:
unsigned int fbo_id;
unsigned int depth_buffer;
int m_FBOWidth, m_FBOHeight;
unsigned int m_TextureID;
void initFBO() {
m_FBOWidth = screen_width;
m_FBOHeight = screen_height;
glGenRenderbuffers(1, &depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_FBOWidth, m_FBOHeight);
glGenTextures(1, &m_TextureID);
glBindTexture(GL_TEXTURE_2D, m_TextureID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_FBOWidth, m_FBOHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo_id);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_TextureID, 0);
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Here is my drawing box code, which just takes a transformation matrix and calls the appropriate functions. The current values of P is a projection matrix, and an identity matrix for the view matrix (V).
void drawBox(const Matrix4& M) {
const Matrix4 MVP = M * V * P;
if (boundshader) {
glUniformMatrix4fv((*boundshader)("MVP"), 1, GL_FALSE, &MVP[0]);
}
glBindVertexArray(vaoID);
glDrawElements(GL_TRIANGLES, sizeof(cube.polygon)/sizeof(cube.polygon[0]), GL_UNSIGNED_INT, 0);
}
void drawStaticBox() {
Matrix4 M(1);
translate(M, Vector3(0,0,-50));
drawBox(M);
}
void drawRotatingBox() {
Matrix4 M(1);
rotate(M, rotation(Vector3(1, 0, 0), rotation_x));
rotate(M, rotation(Vector3(0, 1, 0), rotation_y));
rotate(M, rotation(Vector3(0, 0, 1), rotation_z));
translate(M, Vector3(0,0,-50));
drawBox(M);
}
And the display function called by GLUT.
void OnRender() {
/////////////////////////////////////////
// Render to FBO
glClearColor(0, 0, 0.2f,0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
glViewport(0, 0, m_FBOWidth, m_FBOHeight);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
GL_CHECK_ERRORS
colorshader.Use();
boundshader = &colorshader;
drawRotatingBox();
colorshader.UnUse();
/////////////////////////////////////////
// Render to Window
glClearColor(0, 0, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, screen_width, screen_height);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
GL_CHECK_ERRORS
texshader.Use();
boundshader = &texshader;
glBindTexture(GL_TEXTURE_2D, m_TextureID);
drawStaticBox();
texshader.UnUse();
// Swap le buffers
glutSwapBuffers();
}
And... the obligatory texture shader code
vertex
#version 330
in vec2 vUV;
in vec3 vVertex;
smooth out vec2 vTexCoord;
uniform mat4 MVP;
void main()
{
vTexCoord = vUV;
gl_Position = MVP*vec4(vVertex,1);
}
fragment
#version 330
smooth in vec2 vTexCoord;
out vec4 vFragColor;
uniform sampler2D textureMap;
void main(void)
{
vFragColor = texture(textureMap, vTexCoord);
}
The following is what is rendered when not using the FBO logic:
What is rendered to the FBO http://k.minus.com/jiP7kTOSLLvHk.jpg
... Help?
Any ideas on what I may be doing wrong?
Further source available on request.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
无需仔细查看您的代码,这是一些肯定有效的示例 FBO 代码(将茶壶动画化为纹理,将纹理绘制到旋转立方体的侧面)。
仅供参考,以找到有效的东西。
Without looking closely at your code, this is some example FBO code that works for sure (animates the Teapot to a texture, draws the texture to the sides of a spinning cube).
Just for reference to have something that works.
不确定为什么要乘以着色器中的矩阵。假设您想要在屏幕上拉伸渲染到纹理纹理,您只需定义 4 个顶点(x 和 y 上从 -1 到 1),然后将它们传递到着色器(如果您正在绘制,则为 4 个顶点)当然是带有 2 个三角形的条带)。
在着色器中只需将顶点乘以 0.5 再加上 0.5 即可获得纹理坐标。因此,您不需要传递纹理坐标,因为您可以直接在顶点着色器中生成它们。如果将顶点定义为 -1 到 1,则它们已经在屏幕空间中,因此除了从顶点着色器发出它们之外,您不需要对它们执行任何操作。
Not sure why you're multiplying by a matrix in the shader. Assuming you're wanting to stretch the render-to-texture texture across the screen, you simply need to define 4 vertices, from -1 to 1 on x and y, and pass these into the shader (4 vertex if you're drawing a strip with 2 triangles of course).
In the shader just multiply the vertex by 0.5 and add 0.5 to get the texture coordinates. So you don't need to pass texture coordinates in as you can generate these directly in the vertex shader. The vertices are already in screen space if you define them as -1 to 1, so you don't need to do anything with them except emit them from the vertex shader.
正如 Jari Komppa 在 GameDev.stackexchange 上指出的,以及 neodelphi 作为我主要帖子的评论。
纹理坐标是错误的(或者在我的例子中,没有通过)。
As was pointed out by Jari Komppa on GameDev.stackexchange, and neodelphi as a comment on my main post.
The texture coordinates were wrong (or in my case, not passed).