14

众所周知,openGL 使用左/下为 0/0 的像素数据方向,而世界其他地方(包括几乎所有图像格式)使用左/上。多年来,这一直是无休止的担忧(至少对我而言),我仍然无法想出一个好的解决方案。

在我的应用程序中,我想支持以下图像数据作为纹理:

  1. 来自各种图像源的图像数据(包括静止图像、视频文件和实时视频)
  2. 通过将帧缓冲区复制到主存储器获取的图像数据 ( glReadPixels)
  3. 通过将帧缓冲区抓取到纹理获取的图像数据 ( glCopyTexImage)

(案例 #1 提供自上而下方向的图像(在大约 98% 的情况下;为简单起见,我们假设所有“外部图像”都具有自上而下的方向);#2 和 #3 具有自下而上的方向)

我希望能够将所有这些纹理应用于各种任意复杂的对象(例如从磁盘读取的 3D 模型,其中存储了纹理坐标信息)。

因此我想要一个对象的纹理坐标的单一表示。渲染对象时,我不想被图像源的方向所困扰。(直到现在,我总是topdown在纹理 ID 旁边带有一个 -flag,它在实际设置纹理坐标时使用。我想摆脱这个笨拙的黑客!

基本上我看到了解决问题的三种方法。

  1. 确保所有图像数据都处于“正确”(在 openGL 术语中这是颠倒的)方向,转换所有“不正确”数据,然后将其传递给 openGL
  2. 根据图像方向提供不同的纹理坐标(自下而上图像为 0..1,自上而下图像为 1..0)
  3. 翻转 gfx 卡上的图像

在过去我一直在做#1,但结果太慢了。我们想不惜一切代价避免复制像素缓冲区。

所以几年前我已经切换到#2,但维护起来很复杂。我真的不明白为什么我应该携带原始图像的元数据,一旦我将图像传输到 gfx 卡并有一个漂亮的小抽象“纹理”对象。我正在最终将我的代码转换为 VBO,并且希望避免更新我的 texcoord 数组,因为我使用的是相同大小但方向不同的图像!

剩下的#3,我从来没有为我工作过(但我相信它一定很简单)。直觉上,我想使用类似glPixelZoom(). 这适用于glDrawPixels()(但谁在现实生活中使用它?),并且 afaik 它应该适用于glReadPixels(). 后者很棒,因为它至少允许我为主内存中的所有图像强制一个相当快的同质像素方向(自上而下) 。

但是,似乎这glPixelZoom()对通过 传输的数据没有影响glTexImage2D,更不用说glCopyTex2D(),所以从主存储器像素生成的纹理都将颠倒(我可以忍受,因为这只意味着我必须将所有传入的 texcoords 转换为加载它们时自上而下)。现在剩下的问题是,我还没有找到一种方法将帧缓冲区复制到glCopyTex(Sub)Image可以与那些自上而下的texcoords一起使用的纹理(使用)(即:使用时如何翻转图像glCopyTexImage()

这个简单的问题有解决方案吗?快速、易于维护并在 openGL-1.1 到 4.x 上运行的东西?

啊,理想情况下,它适用于二次幂和非二次幂(或矩形)纹理。(尽可能……)

4

2 回答 2

11

这个简单的问题有解决方案吗?快速、易于维护并在 openGL-1.1 到 4.x 上运行的东西?

不。

在像素上传时无法更改像素数据的方向。没有方法可以原位改变纹理的方向。改变纹理方向(除了下载、翻转和重新上传之外)的唯一方法是使用从包含源纹理的帧缓冲区到包含目标纹理的帧缓冲区的倒置帧缓冲区 blit。并且glFramebufferBlit不适用于任何不支持 GL 2.x 的旧硬件。

所以你将不得不做其他人所做的事情:在上传之前翻转你的纹理。或者更好的是,翻转磁盘上的纹理,然后加载它们而不翻转它们。

然而,如果你真的,真的不想翻转数据,你可以简单地让你的所有着色器采用一个制服,告诉他们是否反转其纹理坐标数据的 Y。反转不应该只是一个乘法/加法运算。这可以在顶点着色器中完成以最小化处理时间。

或者,如果你在固定函数的黑暗时代编码,你可以应用一个反转 Y 的纹理矩阵。

于 2013-06-01T18:22:10.647 回答
2

为什么不改变将纹理映射到多边形的方式?我使用这个映射坐标 { 0, 1, 1, 1, 0, 0, 1, 0 } 作为原点左上角,这个映射坐标 { 0, 0, 1, 0, 0, 1, 1, 1 } 作为原点底部左边。然后你不需要手动切换你的图片。

有关将纹理映射到多边形的更多详细信息,请参见此处:http: //iphonedevelopment.blogspot.de/2009/05/opengl-es-from-ground-up-part-6_25.html

于 2013-12-03T23:02:29.777 回答