【问题标题】:Low resolution render to texture result when using perspective projection使用透视投影时低分辨率渲染到纹理结果
【发布时间】:2012-09-05 10:15:57
【问题描述】:

我目前正在为 iPhone 开发一个相机应用程序,在该应用程序中我获取相机输入,将其转换为 OpenGL 纹理,然后将其映射到 3D 对象(目前为透视投影中的平面,为简单起见)。 在将相机输入映射到这个 3D 平面后,我将这个 3D 场景渲染到一个纹理,然后将其用作正交空间中平面的新纹理(在我的片段着色器中应用额外的过滤器)。

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

比较:

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

我目前没有在我的任何帧缓冲区上使用多重采样,我怀疑是否需要它来解决我的问题,因为正交场景完美运行。

我渲染成的纹理是 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);
}

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

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);    
}

【问题讨论】:

  • 我尝试通过在纹理类上启用 mipmapping 来解决问题,但这并没有解决问题。
  • 要弄清楚这里出了什么问题,显示您用于平面的位置/纹理坐标值以及您正在使用的矩阵可能会更有用。跨度>
  • @bitshiftcop 解决这个问题成功了吗?

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


【解决方案1】:

我会假设纹理映射与透视投影不精确。

你能用检查器替换相机胶卷图像吗(象棋网格,单元格大小为 1px)?然后比较正交和透视投影中的渲染检查器 - 网格不应模糊。如果是,那么问题就出在投影矩阵上——它需要一些偏差来进行直接的纹素到像素映射。

如果您有设备,您可以通过 XCode 中的OpenGL frame capture 功能查看渲染步骤 - 您将看到图像何时变得模糊。

至于 mipmapping,它不适用于动态创建的纹理。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 我试过移动飞机,但模糊并没有消失。
    • 你搬了多少钱?如果使用 iPhone 4 模拟器,它将在不同方向的 x、y 上尝试 0.25 像素。
    • 我正在我的 iPhone 4S 上进行测试,我正在以 0.05 像素的步长移动,我尝试了很多步骤,但没有一个能提供更好甚至稍微更好的结果。我会继续尝试上面提到的其他纹理和棋盘格图案。
    • Okej。好吧,那我的回答似乎不能解决你的问题。
    【解决方案3】:

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

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

    我通过更改我的 3D 平面的纹理坐标合并了这两个步骤,这样我就可以直接在这个平面上使用原始相机纹理。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-25
      • 2016-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多