最近我一直在学习有关OpenGL(3.3核心)的知识,今天我试图将Tilemap绘图从使用Texture Atlas转换为使用Array Texture。主要原因是它避免了瓷砖之间的渗色。
这非常容易实现,并且可以与我的简单tileset图像一起工作,该图像只有3个垂直放置的tile。但是,一旦我尝试了一个较大的tileet图像(每行有一个以上的tile),它就会崩溃,我得到的只是垃圾。
迅速找到了原因:当tileet图像中每行只有一个tile时,单个tile的像素(rgba字节)是连续的。例如,在32x32的图块上,第一行像素为pixel(1) - pixel(32)
,第二行像素为pixel(33) - pixel(64)
,依此类推。但是,当每行有多个图块时,pixel(33) - pixel(64)
不再是第一图块的第二行,而是第二图块的第一行。 OpenGL无法创建正确的纹理,因为单个图块的像素不再连续。
所以我想出了以下代码来手动为每个图块创建纹理:
// Load pixel bytes
var data = bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppArgb
);
byte[] pixels = new byte[data.Stride * data.Height];
System.Runtime.InteropServices.Marshal.Copy(data.Scan0, pixels, 0, pixels.Length);
bitmap.UnlockBits(data);
int bytes_per_tile_row = tile_width * 4;
int bytes_per_image_row = tiles_per_row * bytes_per_tile_row;
// Fill texture (one tile at a time)
byte[] tile_pixels = new byte[tile_width * tile_height * 4];
for (int y = 0; y < tiles_per_column; y++) {
for (int x = 0; x < tiles_per_row; x++) {
int index = x * bytes_per_tile_row + y * bytes_per_image_row * tile_height;
for (int i = 0; i < tile_height; i++) {
Array.Copy(pixels, index, tile_pixels, bytes_per_tile_row * i, bytes_per_tile_row);
index += bytes_per_image_row;
}
GL.TexSubImage3D(TextureTarget.Texture2DArray, 0,
0, 0, x + y * tiles_per_row,
tile_width, tile_height, 1,
PixelFormat.Bgra, PixelType.UnsignedByte, tile_pixels
);
}
}
这可行,但感觉更像是一种解决方法,而不是解决方案。
我想知道是否有更好的方法来解决这个问题?