使用透视投影时,低分辨率渲染到纹理结果

时间:2012-09-05 10:15:58

标签: iphone opengl-es opengl-es-2.0

我目前正在开发一款适用于iPhone的相机应用程序,我在其中将相机输入转换为OpenGL纹理,然后将其映射到3D对象(目前是透视投影中的平面,为此简单)。 将摄像机输入映射到此3D平面后,我将此3D场景渲染为纹理,然后将其用作正交空间中平面的新纹理(在我的片段着色器中应用其他滤镜)。

只要我将所有内容保留在正交投影中,我的渲染纹理的分辨率就相当高。但是从我投影透视投影的那一刻起,渲染纹理的分辨率非常低。

比较:

Resolution comparison

如您所见,与其他两张图像相比,最后一张图像的分辨率非常低。所以我猜测我做错了什么。

我目前没有在我的任何一个帧缓冲器上使用多重采样,我怀疑是否需要它来解决我的问题,因为正交场景工作正常。

我渲染的纹理是2048x2048(最终将作为图像输出到iPhone相机胶卷)。

以下是我认为可能相关的源代码的一些部分:

创建输出到屏幕的帧缓冲区的代码:

// Color renderbuffer
glGenRenderbuffers(1, &colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
[context renderbufferStorage:GL_RENDERBUFFER 
                 fromDrawable:(CAEAGLLayer*)glView.layer];

// Depth renderbuffer
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);

// Framebuffer
glGenFramebuffers(1, &defaultFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFrameBuffer);

// Associate renderbuffers with framebuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
      GL_RENDERBUFFER, colorRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 
      GL_RENDERBUFFER, depthRenderbuffer);

TextureRenderTarget类:

void TextureRenderTarget::init()
{
    // Color renderbuffer
    glGenRenderbuffers(1, &colorRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, 
           width, height);

    // Depth renderbuffer
    glGenRenderbuffers(1, &depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 
           width, height);

    // Framebuffer
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

    // Associate renderbuffers with framebuffer
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
          GL_RENDERBUFFER, colorRenderBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 
          GL_RENDERBUFFER, depthRenderbuffer);

    // Texture and associate with framebuffer
    texture = new RenderTexture(width, height);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
          GL_TEXTURE_2D, texture->getHandle(), 0);

    // Check for errors
    checkStatus();
}

void TextureRenderTarget::bind() const
{
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
}



void TextureRenderTarget::unbind() const
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);
}

最后,关于我如何创建渲染纹理并用像素填充它的片段:

void Texture::generate()
{
    // Create texture to render into
    glActiveTexture(unit);
    glGenTextures(1, &handle);
    glBindTexture(GL_TEXTURE_2D, handle);

    // Configure texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

void Texture::setPixels(const GLvoid* pixels)
{
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, 
         GL_UNSIGNED_BYTE, pixels);
    updateMipMaps();
}

void Texture::updateMipMaps() const
{
    glBindTexture(GL_TEXTURE_2D, handle);
    glGenerateMipmap(GL_TEXTURE_2D);
}

void Texture::bind(GLenum unit)
{
    this->unit = unit;

    if(unit != -1)
    {
        glActiveTexture(unit);
        glBindTexture(GL_TEXTURE_2D, handle);
    }
    else
    {
        cout << "Texture::bind -> Couldn't activate unit -1" << endl;
    }
}

void Texture::unbind()
{
    glBindTexture(GL_TEXTURE_2D, 0);    
}

3 个答案:

答案 0 :(得分:6)

我认为纹理映射与透视投影不完全相同。

您可以通过检查器(1px单元大小的国际象棋网格)替换相机胶卷图像吗?然后在正交和透视投影中比较渲染的检查器 - 网格应该不模糊。如果是,那么问题在于投影矩阵 - 它需要一些偏向直接纹素到像素的映射。

如果你有设备,你可以通过XCode中的OpenGL frame capture功能查看渲染步骤 - 在那里你会看到图像的确切时间变得模糊。

至于mipmapping,将它用于即时创建的纹理并不好。

答案 1 :(得分:5)

模糊可能是由于平面位于屏幕坐标中的半个像素引起的。由于从正交变换到透视变换会改变平面的位置,因此平面可能不会位于两个变换之间的相同屏幕坐标处。

在标准分辨率显示器上将UIImageView从帧原点(0.0,0.0)移动到(0.5,0.5),在视网膜显示器上移动(0.25,0.25)时会发生类似的模糊。

在这种情况下,纹理非常高的事实可能无济于事,因为实际采样的像素数是有界的。

尝试在屏幕x,y坐标中移动一小段距离,看看模糊是否消失。

答案 2 :(得分:1)

我终于通过合并渲染过程的第一步和第二步解决了我的问题。

用于裁剪和翻转相机纹理并将其渲染为新纹理的第一步。然后,这个新渲染的纹理被映射到一个3D平面上,结果呈现为一个新的纹理。

我通过更改3D平面的纹理坐标来合并这两个步骤,以便我可以将原始相机纹理直接用于此平面。

我不知道造成这两个渲染纹理之间质量损失的确切原因是什么,但作为未来的提示:不要渲染到纹理并重新使用该结果来渲染纹理。将所有这些合并在一起对于性能更好,并且还避免了色移问题。