从tileet图像创建2D阵列纹理的最佳方法是什么?

时间:2019-12-15 10:40:19

标签: c# opengl opentk opengl-3

最近我一直在学习有关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
        );
    }
}

这可行,但感觉更像是一种解决方法,而不是解决方案。
我想知道是否有更好的方法来解决这个问题?

0 个答案:

没有答案