如何在 glTexImage2D 中使用动态大小的纹理数组?

Posted

技术标签:

【中文标题】如何在 glTexImage2D 中使用动态大小的纹理数组?【英文标题】:How can I use a dynamically sized texture array with glTexImage2D? 【发布时间】:2009-03-24 20:55:19 【问题描述】:

目前,我可以加载我创建的静态大小的纹理。在本例中为 512 x 512。

此代码来自标题:

#define TEXTURE_WIDTH 512
#define TEXTURE_HEIGHT 512

GLubyte textureArray[TEXTURE_HEIGHT][TEXTURE_WIDTH][4];

glTexImage2D的用法如下:

glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA,
    TEXTURE_WIDTH, TEXTURE_HEIGHT,
    0, GL_RGBA, GL_UNSIGNED_BYTE, textureArray);

这就是我填充数组的方式(粗略的例子,不是我的代码的精确副本):

for (int i = 0; i < getTexturePixelCount(); i++)

    textureArray[column][row][0] = (GLubyte)pixelValue1;
    textureArray[column][row][1] = (GLubyte)pixelValue2;
    textureArray[column][row][2] = (GLubyte)pixelValue3;
    textureArray[column][row][3] = (GLubyte)pixelValue4;

如何更改它以不再需要 TEXTURE_WIDTH 和 TEXTURE_HEIGHT?也许我可以使用指针样式数组并动态分配内存...

编辑:

我想我看到了问题,在 C++ 中它真的无法完成。 Budric 指出的解决方法是使用一维数组,但使用所有 3 个维度相乘来表示索引:

GLbyte *array = new GLbyte[xMax * yMax * zMax];

要访问,例如 1/2/3 的 x/y/z,您需要这样做:

GLbyte byte = array[1 * 2 * 3];

但是,问题是,我认为glTexImage2D 函数不支持这一点。谁能想到一个适用于这个 OpenGL 函数的解决方法?

编辑 2:

注意 OpenGL 开发人员,这可以通过使用一维像素数组来克服...

[0]:第 0 列 > [1]:第 0 行 > [2]:通道 0 ... n > [n]:第 1 行 ... n > [n]:第 1 列 .. n

... 无需使用 3 维数组。在这种情况下,我不得不使用这项工作,因为 3 维数组在 C++ 中显然是不可能的。

【问题讨论】:

您不能简单地将索引相乘。它是 (rowIndex * numColumns * numColourComponents + columnIndex + colourComponent); 糟糕。应该是 (rowIndex * numColumns * numColourComponents + columnIndex*numColourComponents + colourComponent); 【参考方案1】:

好的,因为这花了我很长时间才弄清楚,这里是:

我的任务是使用动态纹理数组实现 OpenGL 红皮书(9-1,p373,第 5 版)中的示例。

示例使用:

static GLubyte checkImage[checkImageHeight][checkImageWidth][4];

如您所料,尝试分配一个 3 维数组是行不通的。某事。像这样工作:

GLubyte***checkImage;
checkImage = new GLubyte**[HEIGHT];

for (int i = 0; i < HEIGHT; ++i)

  checkImage[i] = new GLubyte*[WIDTH];

  for (int j = 0; j < WIDTH; ++j)
    checkImage[i][j] = new GLubyte[DEPTH];

你必须使用一维数组

unsigned int depth = 4;

GLubyte *checkImage = new GLubyte[height * width * depth];

您可以使用此循环访问元素:

for(unsigned int ix = 0; ix < height; ++ix)

  for(unsigned int iy = 0; iy < width; ++iy)
  
    int c = (((ix&0x8) == 0) ^ ((iy&0x8)) == 0) * 255;

    checkImage[ix * width * depth + iy * depth + 0] = c;   //red
    checkImage[ix * width * depth + iy * depth + 1] = c;   //green
    checkImage[ix * width * depth + iy * depth + 2] = c;   //blue
    checkImage[ix * width * depth + iy * depth + 3] = 255; //alpha
  

别忘了正确删除:

delete [] checkImage;

希望这会有所帮助...

【讨论】:

也帮了我一把!所以请投票...这是 OpenGL 的小复杂之一【参考方案2】:

你可以使用

int width = 1024;
int height = 1024;
GLubyte * texture = new GLubyte[4*width*height];
...
glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA,
    width, height,
    0, GL_RGBA, GL_UNSIGNED_BYTE, textureArray);
delete [] texture;         //remove the un-needed local copy of the texture;

但是,您仍然需要在 glTexImage2D 调用中为 OpenGL 指定宽度和高度。此调用复制纹理数据,并且该数据由 OpenGL 管理。您可以随心所欲地删除、调整大小、更改原始纹理数组,它不会对您指定给 OpenGL 的纹理产生任何影响。

编辑: C/C++ 只处理一维数组。您可以执行 texture[a][b] 的事实在编译时由编译器隐藏和转换。编译器必须知道列数并且会做texture[a*cols + b]。

使用类隐藏分配,获取纹理。

出于学术目的,如果您真的想要动态多维数组,以下应该可行:

int rows = 16, cols = 16;
char * storage = new char[rows * cols];
char ** accessor2D = new char *[rows];
for (int i = 0; i < rows; i++)

    accessor2D[i] = storage + i*cols;

accessor2D[5][5] = 2;
assert(storage[5*cols + 5] == accessor2D[5][5]);
delete [] accessor2D;
delete [] storage;

请注意,在所有情况下,我都使用一维数组。它们只是指针数组和指向指针的指针数组。这有内存开销。这也适用于没有颜色分量的二维数组。对于 3D 取消引用,这变得非常混乱。不要在你的代码中使用它。

【讨论】:

嗯,这行得通,只有在给数组赋值时,我得到这个错误:数组下标的无效类型'unsigned char[int]' 你在使用纹理[i][j]吗?您不能将其与上面的代码一起使用。纹理[行 * 宽度 + 列]。 @Budric,我的数组需要有 3 个维度,而不是 2 个维度。我以纹理 [column][row][channel] 的样式访问它【参考方案3】:

你总是可以把它放在一个类中。如果你从一个文件中加载图像,你会得到其余数据的高度和宽度(你还能如何使用文件?),你可以将它们存储在一个包装文件加载的类中,而不是使用预处理器定义.比如:

class ImageLoader

...
  ImageLoader(const char* filename, ...);
...
  int GetHeight();
  int GetWidth();
  void* GetDataPointer();
...
;

你可以将 glTexImage2d 的函数调用隐藏在其中。

class GLImageLoader

...
  ImageLoader(const char* filename, ...);
...
  GLuint LoadToTexture2D(); // returns texture id
...
;

【讨论】:

以上是关于如何在 glTexImage2D 中使用动态大小的纹理数组?的主要内容,如果未能解决你的问题,请参考以下文章

在 glTexImage2D 中我选择与在着色器中采样不同的内部格式时会怎样?

如何在collectionViewCell中使用动态大小的scrollView

OpenGL API 之 glTexImage2D

glTexImage2D 中的 ByteBuffer.wrap() 导致过多的垃圾收集

如何向 Shader 传递一个巨大的数组

对符号 glTexImage2D 的未定义引用