从“1D"映射纹理到“2D"使用 OpenGL 矩阵变换 [英] Mapping a texture from "1D" to "2D" with OpenGL matrix transformations

查看:18
本文介绍了从“1D"映射纹理到“2D"使用 OpenGL 矩阵变换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(带着这个问题,我试图调查我解决问题的想法 这个另一个)

如果我在内存中有一个尺寸为 widthheight 的标准二维数组,我可以将其转换为长度为 width 的一维数组* height 然后通过 index = x + y * width 对其进行索引.这种映射在为数组分配和释放内存时非常有用,因为内存管理器无需担心将结构打包为 2D,而只需担心每个已分配数组的总长度(如果以 1D 表示).

If I have a standard 2D array of dimensions width and height in memory, I can turn that into a 1D array of length width * height and then index it via index = x + y * width. This mapping is extremely helpful when allocating and freeing memory for the array as the memory manager does not need to worry about packing the structures in 2D but only needs to worry about the overall length of every allocated array if expressed in 1D.

我正在尝试查看是否可以使用相同的方法来管理 OpenGL 纹理的图像内存.这个想法(如上面链接的问题中所述)是通过 bin-packing 将它们(即将它们彼此相邻绘制)放入大纹理中.这有助于在渲染期间最大限度地减少昂贵的纹理绑定操作.

I am trying to see if I can use this same approach for image-memory management for OpenGL textures. The idea (as described in the above linked question) is to combine a whole bunch of needed textures into a single bigger one by bin-packing them (i.e. drawing them next to each other) into the big texture. This helps minimize costly texture-binding operations during rendering.

假设我的大纹理是 8×8 像素(即总共 64 像素):

Let's say my big texture is 8×8 pixels (i.e. 64 pixels total):

8x8 texture:                5x5 image:            4x5 image:

   | 0 1 2 3 4 5 6 7           | 0 1 2 3 4           | 0 1 2 3
---+-----------------       ---+-----------       ---+---------
 0 | . . . . . . . .         0 | A B C D E         0 | a b c d
 1 | . . . . . . . .         1 | F G H I J         1 | e f g h
 2 | . . . . . . . .         2 | K L M N O         2 | i j k l
 3 | . . . . . . . .         3 | P Q R S T         3 | m n o p
 4 | . . . . . . . .         4 | U V W X Y         4 | q r s t
 5 | . . . . . . . .
 6 | . . . . . . . .
 7 | . . . . . . . .

我想在其中存储一个 5×5 的图像和一个 4×5 的图像(即总共 25 + 20 = 45 个像素).从技术上讲,我有大量可用像素,但我无法将这些图像彼此相邻放置到大纹理中,因为这需要一个方向的最小尺寸为 9,而另一个方向的最小尺寸为 5.

And I would like to store a 5×5 image and a 4×5 image in it (i.e. 25 + 20 = 45 pixels total). Technically, I have plenty of pixels available, but I can't place these images next to each other into the big texture as that would require a minimum dimension of 9 in one direction and 5 in the other.

如果我可以简单地将我的 8×8 纹理视为 64 个连续像素的内存并将两个图像映射到其中的 1D 内存块中,我可以在纹理中按如下方式排列图像:8x8 纹理:

If I could simply treat my 8×8 texture as 64 continues pixels of memory and map the two images into 1D blocks of memory inside that, I could arrange the images as follows inside the texture: 8x8 texture:

   | 0 1 2 3 4 5 6 7
---+-----------------
 0 | A B C D E F G H
 1 | I J K L M N O P             
 2 | Q R S T U V W X
 3 | Y a b c d e f g             
 4 | h i j k l m n o             
 5 | p q r s t . . .
 6 | . . . . . . . .
 7 | . . . . . . . .

如果我以 1:1 的比例绘制所有图像,即任何地方都没有小数像素坐标,也不需要任何线性过滤或其他像素混合,是否有可能提出一个我可以使用的变换矩阵使用此纹理绘制 4×5 图像?

If I draw all my images at a scale of 1:1, i.e. no fractional pixel coordinates anywhere and no need for any linear filtering or other pixel blending, is it possible to come up with a transformation matrix that I can use to draw the 4×5 image using this texture?

使用顶点和片段着色器,这看起来可能相当容易(除非我忘记了什么;我还没有尝试过):

With vertex and fragment shaders, this looks like it might be fairly easy (unless I'm forgetting something; I haven't tried this):

  • 顶点着色器将要绘制的图像的四个角映射到以 64×1 图像表示的纹理:

  • The vertex shader maps the four corners of the image to draw to the texture expressed as a 64×1 image:

  • a: (0, 0) →(0 + 0*4 + 25, 0) = (25, 0)     其中25是4×5图像的偏移量
  • d: (3, 0) →(3 + 0*4 + 25, 0) = (28, 0)
  • q: (0, 4) →(0 + 4*4 + 25, 0) = (41, 0)
  • t: (3, 4) →(3 + 4*4 + 25, 0) = (44, 0)
  • a: (0, 0) → (0 + 0*4 + 25, 0) = (25, 0)     where 25 is the offset of the 4×5 image
  • d: (3, 0) → (3 + 0*4 + 25, 0) = (28, 0)
  • q: (0, 4) → (0 + 4*4 + 25, 0) = (41, 0)
  • t: (3, 4) → (3 + 4*4 + 25, 0) = (44, 0)

纹理内其他坐标的插值应该 (?) 然后也映射到整数坐标沿这条线的右侧偏移量

The interpolation of other coordinates inside the texture should (?) then also map to the right offset along this line for integer coordinates

  • a: (0, 25) →(25 % 8, 25/8) = (1, 3)
  • d: (0, 28) →(28 % 8, 28/8) = (4, 3)
  • k: (0, 35) →(35 % 8, 35/8) = (3, 4)
  • q: (0, 41) →(41 % 8, 41/8) = (1, 5)
  • t: (0, 44) →(44 % 8, 44/8) = (4, 5)
  • a: (0, 25) → (25 % 8, 25 / 8) = (1, 3)
  • d: (0, 28) → (28 % 8, 28 / 8) = (4, 3)
  • k: (0, 35) → (35 % 8, 35 / 8) = (3, 4)
  • q: (0, 41) → (41 % 8, 41 / 8) = (1, 5)
  • t: (0, 44) → (44 % 8, 44 / 8) = (4, 5)

不幸的是,自定义着色器需要 OpenGL ES v2.0 或更高版本,这并非在所有设备上都可用.

Unfortunately custom shaders require OpenGL ES v2.0 or better, which is not available on all devices.

是否有可能仅通过 OpenGL ES 1.1 提供的矩阵转换来实现这种映射?

Is it somehow possible to achieve this mapping just via the matrix transformations offered by OpenGL ES 1.1?

推荐答案

我还没有尝试过,但我想把它作为一个想法扔出去:

I haven't tried this yet, but I wanted to throw it out there as an idea already:

更新:我现在试了一下,只需稍作改动就可以很好地工作(见评论)!

假设我的大纹理的宽度为 size,而我要绘制的图像的宽度为 width,并从大纹理中的偏移量 offset 开始纹理,其中 offset 是偏移量的一维表示,即 x + y * size.

Let's say my big texture has width size and the image I want to draw has width width and starts at offset offset inside the big texture, where offset is the 1-D representation of the offset, i.e. x + y * size.

那么,下面的 4x4 矩阵几乎可以实现这个映射:

Then, the following 4x4 matrix will almost achieve this mapping:

     _                                           _
    |      1        width        offset      0    |
    |                                             |
    |   1/size   width/size   offset/size    0    |
M = |                                             |
    |      0          0            0         0    |
    |                                             |
    |_     0          0            0         1   _|

因此,在上面的示例中,要绘制 4×5 的图像,矩阵将是

So, in the example above, to draw the 4×5 image, the matrix would be

 _                    _
|   1    4    25    0  |
|  1/8  1/2  25/8   0  |
|   0    0     0    0  |
|_  0    0     0    1 _|

然后需要使用包含

( x, y, 1, 1 )

因此,例如 k 的坐标(即 (2,2))将映射到:

So, for example the coordinates of k (i.e. (2,2)) will map to:

M*( 2, 2, 1, 1 ) => ( 35, 4.375, 0, 1 )

将被解释为纹理坐标 (35, 4.375).

which will be interpreted as texture coordinate (35, 4.375).

如果我们现在打开最近邻作为插值规则并在 x 方向启用纹理环绕,这应该对应于:

If we now turn on nearest neighbor as the interpolation rule and enable texture wrapping in the x-direction, this should correspond to:

( 3, 4 )

(我在这里使用整数坐标,而在最终实现中,最终坐标需要在 0 到 1 的范围内浮动.这可以通过替换 1 轻松实现size 在矩阵的右下角,因为它最终会出现在输出向量的第四个位置,从而除以其他三个.正如@chbaker0 指出的那样,这只会起作用,但是,如果纹理坐标按照通常的透视划分,如果不是,则整个矩阵M需要除以size才能达到预期的效果.)

(I was using integer coordinates here, whereas in the final implementation, the final coordinates would need to be floats in the range from 0 to 1. This might be achievable very easily by replacing the 1 in the bottom right corner of the matrix with size, since that will end up in the fourth position of the output vector and thus divide the other three. This, as @chbaker0 pointed out, would only work, though, if the texture coordinates are subject to the usual perspective division. If they are not, the entire matrix M needs to be divided by size instead to achieve the desired result.)

这听起来是否合理,或者在我继续尝试实施之前,有人会发现这个问题吗?(可能需要几天时间,因为我必须先做几件事才能获得可测试的应用程序...)

Does this sound reasonable at all or can someone see a problem with this before I go ahead and try to implement this? (Might take me a few days, since I have to do a couple other things first to get to a testable app...)

这篇关于从“1D"映射纹理到“2D"使用 OpenGL 矩阵变换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆