opengl - 比我设置的更小的帧缓冲纹理?
Posted
技术标签:
【中文标题】opengl - 比我设置的更小的帧缓冲纹理?【英文标题】:opengl - framebuffer texture clipped smaller than I set it? 【发布时间】:2011-12-06 14:48:51 【问题描述】:我正在使用 opengl ES 2.0 我正在使用链接到纹理的帧缓冲区来编译(一些简单的元球的)屏幕外渲染,然后将该纹理渲染到主后台缓冲区。
一切看起来都很棒,除了纹理看起来被剪裁了,即。它不是完整的窗口尺寸(一个轴上缺少大约 128 个像素)。截图如下:http://tinypic.com/r/9telwg/7
有什么想法会导致这种情况吗?我阅读here 将glViewport 设置为纹理的大小,但这给了我不同的纵横比,因为纹理metaballsTexture 是正方形(1024x1024)并且我的窗口是768x1024。它也仍然有点剪裁,因为看起来我无法让帧缓冲区足够大,即使纹理大于我的窗口大小。下面是我的代码。当我准备好时,我在渲染期间调用 PrepareToAddMetaballs(),然后连续调用 AddMetaball,现在渲染到我的屏幕外 FBO,然后在我完成后调用 FinishedAddingMetaballs,然后调用 Render() 以显示链接到 FBO 的屏幕外纹理到主后台缓冲区。
#include "Metaballs.h"
#include "s3e.h"
#include "IwGL.h"
#include "Render.h"
#include "vsml.h"
#include <vector>
#include <string>
#include <iostream>
#include "1013Maths.h"
#define GL_RGBA8 0x8058
MetaBalls::MetaBalls() : metaballsTexture(NULL), metaballsShader(NULL)
glGenFramebuffers(1, &myFBO);
metaballTexture[0] = NULL;
metaballTexture[1] = NULL;
metaballTexture[2] = NULL;
CRender::Instance()->CreateTexture("WaterCanvas.png", &metaballsTexture);
CRender::Instance()->CreateTexture("metaball.pvr", &metaballTexture[0]);
CRender::Instance()->CreateTexture("metaball-1.png", &metaballTexture[1]);
CRender::Instance()->CreateTexture("metaball-2.png", &metaballTexture[2]);
CRender::Instance()->CreateShader("Shaders/metaballs.fs", "Shaders/metaballs.vs", &metaballsShader);
glBindFramebuffer(GL_FRAMEBUFFER, myFBO);
// Attach texture to frame buffer
glBindTexture(GL_TEXTURE_2D, metaballsTexture->m_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, metaballsTexture->m_id, 0);
glClearColor(1,1,1,0);
glClear(GL_COLOR_BUFFER_BIT);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::string error = "Metaballs framebuffer incomplete";
std::cerr << error << std::endl;
throw error;
float w = PTM_DOWNSCALE(float(metaballsTexture->GetWidth()));
float h = PTM_DOWNSCALE(float(metaballsTexture->GetHeight()));
CRender::Instance()->BuildQuad(
tVertex( b2Vec3(0,0,0), b2Vec2(0,1) ),
tVertex( b2Vec3(w,0,0), b2Vec2(1,1) ),
tVertex( b2Vec3(w,h,0), b2Vec2(1,0) ),
tVertex( b2Vec3(0,h,0), b2Vec2(0,0) ),
buffer);
MetaBalls::~MetaBalls()
CRender::Instance()->ReleaseShader(metaballsShader);
CRender::Instance()->ReleaseTexture(metaballsTexture);
CRender::Instance()->ReleaseTexture(metaballTexture[0]);
CRender::Instance()->ReleaseTexture(metaballTexture[1]);
CRender::Instance()->ReleaseTexture(metaballTexture[2]);
glDeleteFramebuffers(1, &myFBO);
void MetaBalls::PrepareToAddMetaballs(b2Vec3& paintColour)
// bind render to texture
glBindFramebuffer(GL_FRAMEBUFFER, myFBO);
// Set our viewport so our texture isn't clipped (appears stretched and clipped)
// glViewport(0, 0, metaballsTexture->GetWidth(), metaballsTexture->GetHeight());
glClearColor(paintColour.x, paintColour.y, paintColour.z, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
void MetaBalls::FinishedAddingMetaballs()
glBindFramebuffer(GL_FRAMEBUFFER, NULL);
// CRender::Instance()->SetWindowViewport();
void MetaBalls::AddMetaball(float x, float y, uint size)
// render the metaball texture to larger texture
VSML::setIdentityMatrix(pTransform);
pTransform[12] = PTM_DOWNSCALE(x);
pTransform[13] = PTM_DOWNSCALE(y+4); // the +4 is for a bit of overlap with land
float oldview[16];
float identity[16];
VSML::setIdentityMatrix(identity);
memcpy(oldview, CRender::Instance()->GetViewMatrix(), sizeof(float)*16);
memcpy(CRender::Instance()->GetViewMatrix(),identity, sizeof(float)*16);
CRender::Instance()->DrawSprite(metaballTexture[size], pTransform, 1.0f, true);
memcpy(CRender::Instance()->GetViewMatrix(),oldview, sizeof(float)*16);
void MetaBalls::Render()
VSML::setIdentityMatrix(pTransform);
pTransform[12] = PTM_DOWNSCALE(-128);
pTransform[13] = PTM_DOWNSCALE(-256);
// render our metaballs texture using alpha test shader
CRender::Instance()->BindShader(metaballsShader);
CRender::Instance()->BindTexture(0, metaballsTexture);
CRender::Instance()->SetMatrix(metaballsShader, "view", CRender::Instance()->GetViewMatrix());
CRender::Instance()->SetMatrix(metaballsShader, "world", pTransform);
CRender::Instance()->SetMatrix(metaballsShader, "proj", CRender::Instance()->GetProjMatrix());
CRender::Instance()->SetBlending(true);
CRender::Instance()->DrawPrimitives(buffer);
CRender::Instance()->SetBlending(false);
=====================
编辑
啊哈!知道了。我在任何地方都没有找到这个例子,但我通过调整透视矩阵来修复它。它在工作时设置为 1024x768,但窗口大小为 768x1024,投影矩阵和视口都在变化。通过手动将每个设置为 1024x768(我选择使用常量),元球以适当的纵横比正确呈现在屏幕外。他们的 1024x1024 纹理被渲染为一个广告牌,其纵横比又好又锐利。完成后,我将它们恢复为应用程序其余部分使用的内容。以下是工作代码:
#include "Metaballs.h"
#include "s3e.h"
#include "IwGL.h"
#include "Render.h"
#include "vsml.h"
#include <vector>
#include <string>
#include <iostream>
#include "1013Maths.h"
MetaBalls::MetaBalls() : metaballsTexture(NULL), metaballsShader(NULL)
glGenFramebuffers(1, &myFBO);
metaballTexture[0] = NULL;
metaballTexture[1] = NULL;
metaballTexture[2] = NULL;
CRender::Instance()->CreateTexture("WaterCanvas.png", &metaballsTexture);
CRender::Instance()->CreateTexture("metaball.pvr", &metaballTexture[0]);
CRender::Instance()->CreateTexture("metaball-1.png", &metaballTexture[1]);
CRender::Instance()->CreateTexture("metaball-2.png", &metaballTexture[2]);
CRender::Instance()->CreateShader("Shaders/metaballs.fs", "Shaders/metaballs.vs", &metaballsShader);
glBindFramebuffer(GL_FRAMEBUFFER, myFBO);
// Attach texture to frame buffer
glBindTexture(GL_TEXTURE_2D, metaballsTexture->m_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, metaballsTexture->m_id, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::string error = "Metaballs framebuffer incomplete";
std::cerr << error << std::endl;
throw error;
float w = PTM_DOWNSCALE(float(metaballsTexture->m_width));
float h = PTM_DOWNSCALE(float(metaballsTexture->m_height));
CRender::Instance()->BuildQuad(
tVertex( b2Vec3(0,0,0), b2Vec2(0,1) ),
tVertex( b2Vec3(w,0,0), b2Vec2(1,1) ),
tVertex( b2Vec3(w,h,0), b2Vec2(1,0) ),
tVertex( b2Vec3(0,h,0), b2Vec2(0,0) ),
buffer);
// return to default state
glBindFramebuffer(GL_FRAMEBUFFER, 0);
MetaBalls::~MetaBalls()
CRender::Instance()->ReleaseShader(metaballsShader);
CRender::Instance()->ReleaseTexture(metaballsTexture);
CRender::Instance()->ReleaseTexture(metaballTexture[0]);
CRender::Instance()->ReleaseTexture(metaballTexture[1]);
CRender::Instance()->ReleaseTexture(metaballTexture[2]);
glDeleteFramebuffers(1, &myFBO);
void MetaBalls::PrepareToAddMetaballs(b2Vec3& paintColour)
// bind render to texture
glBindFramebuffer(GL_FRAMEBUFFER, myFBO);
// Set orthographic projection
cfloat w = SCREEN_WIDTH / PTM_RATIO;
cfloat h = SCREEN_HEIGHT / PTM_RATIO;
VSML::ortho(-w, 0, -h, 0, 0.0f, -1.0f, CRender::Instance()->m_Proj);
// Set our viewport so our texture isn't clipped
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glClearColor(paintColour.x, paintColour.y, paintColour.z, 0.1f);
glClear(GL_COLOR_BUFFER_BIT);
void MetaBalls::FinishedAddingMetaballs()
glBindFramebuffer(GL_FRAMEBUFFER, NULL);
CRender::Instance()->SetWindowViewport();
void MetaBalls::AddMetaball(float x, float y, uint size)
// render the metaball texture to larger texture
VSML::setIdentityMatrix(pTransform);
pTransform[12] = PTM_DOWNSCALE(x);
pTransform[13] = PTM_DOWNSCALE(y);
float oldview[16];
float identity[16];
VSML::setIdentityMatrix(identity);
memcpy(oldview, CRender::Instance()->GetViewMatrix(), sizeof(float)*16);
memcpy(CRender::Instance()->GetViewMatrix(),identity, sizeof(float)*16);
CRender::Instance()->DrawSprite(metaballTexture[size], pTransform, 1.0f, true);
memcpy(CRender::Instance()->GetViewMatrix(),oldview, sizeof(float)*16);
void MetaBalls::Render()
VSML::setIdentityMatrix(pTransform);
pTransform[12] = PTM_DOWNSCALE(0);
pTransform[13] = PTM_DOWNSCALE(-256);
// render our metaballs texture using alpha test shader
CRender::Instance()->BindShader(metaballsShader);
CRender::Instance()->BindTexture(0, metaballsTexture);
CRender::Instance()->SetMatrix(metaballsShader, "view", CRender::Instance()->GetViewMatrix());
CRender::Instance()->SetMatrix(metaballsShader, "world", pTransform);
CRender::Instance()->SetMatrix(metaballsShader, "proj", CRender::Instance()->GetProjMatrix());
CRender::Instance()->SetBlending(true);
CRender::Instance()->DrawPrimitives(buffer);
CRender::Instance()->SetBlending(false);
【问题讨论】:
我已经设法通过在渲染时将变换 x 和 y 设置为 0 来使其在 1024x768 中全部可见,但是如果我将窗口设置为 768x1024,它的底部会被剪裁(256 像素我想)。我认为这是因为我仍在水平方向绘制它,但我将视图矩阵旋转了 90 度(当 ipad 旋转时)。所以看起来屏幕外渲染的部分被剪掉了?这是因为视口吗? 【参考方案1】:您是否根据纹理的大小设置视口?我没有在您的代码上找到任何视口设置...
【讨论】:
嗨,是的,你可以看到我已经在 PrepareToAddMetaballs 函数中尝试过这个,它目前被注释掉了,虽然它只是稍微向宽度方向拉伸纹理,但剪裁问题仍然存在。跨度> 你设置透视矩阵了吗? 我刚刚发现一个帖子有同样的问题,但没有解决方案,这可能有助于澄清。 ***.com/questions/5041098/… 透视矩阵也需要调整,见上。对于那些阅读,还要注意它在工作时看起来分辨率很差,因此有必要调整我的 metaballs 着色器中的容差。不知道为什么会这样,但在我调整后它实现了清晰的每像素抗锯齿。 由于同样的问题,我花了 1 小时了解图像后处理有什么问题。以上是关于opengl - 比我设置的更小的帧缓冲纹理?的主要内容,如果未能解决你的问题,请参考以下文章
OpenGLES 2.0 帧缓冲区可以同时绑定到纹理和渲染缓冲区吗?
OpenGL 帧缓冲区 - 渲染到纹理创建带有主帧缓冲区内容的纹理