如何使用具有动态大小的纹理数组与glTexImage2D?

3

目前,我可以加载一个我创建的静态大小的纹理。在这种情况下,它是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指出的那样,解决方法是使用单个维度数组,但使用所有三个维度相乘来表示将是索引的内容:

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 ... 不需要使用三维数组。在这种情况下,我必须使用此解决方法,因为在C++中显然无法严格使用三维数组。

1
你不能简单地将索引相乘。它是(rowIndex * numColumns * numColourComponents + columnIndex + colourComponent); - Budric
1
糟糕,应该是(rowIndex * numColumns * numColourComponents + columnIndex*numColourComponents + colourComponent); - Budric
3个回答

5

好的,由于这个问题让我花费了很长时间才解决,现在将它分享出来:

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

该示例使用:

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

尝试分配一个三维数组,如你所想,这无法完成任务。像这样的尝试不会奏效:
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的那些小复杂性之一。 - rajaditya_m

4

您可以使用

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;

请注意,所有情况下我都使用了一维数组。它们只是指针数组和指向指针的指针数组。这会带来内存开销。此外,这是针对没有颜色分量的二维数组进行的。对于三维解引用,这变得非常混乱。不要在你的代码中使用这个。


嗯,这个方法是可行的,只是当给数组赋值时,我遇到了这个错误:无效类型“unsigned char[int]”用于数组下标。 - Nick Bolton
你是否在使用texture[i][j]?根据上面的代码,你不能使用那个。取而代之,可以使用texture[row * width + column]。 - Budric
@Budric,我的数组需要有三个维度而不是两个。我正在使用的访问方式是texture[column][row][channel]。 - Nick Bolton

1
你可以把它封装在一个类中。如果你从文件中加载图像,你可以在获取其余数据时同时获取高度和宽度(否则你怎么使用该文件?),你可以将它们存储在一个包装文件加载的类中,而不是使用预处理器定义。类似这样:
class ImageLoader
{
...
  ImageLoader(const char* filename, ...);
...
  int GetHeight();
  int GetWidth();
  void* GetDataPointer();
...
};

更好的是,您可以将对glTexImage2d函数的调用隐藏在其中。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接