正确使用 GLTexSubImage3D 的问题

Problems using GLTexSubImage3D correctly

我问的 问题的续集。在那个问题中,我展示了如何为 opengl 提供 3 个纹理并渲染其中一个。我正在尝试使用以下代码编辑这些纹理之一而不替换它们:

public void Replace( string name, int index)
{
    Bitmap bmp = new Bitmap(name); //assumed to be MasterSize
    BitmapData thedata = bmp.LockBits(new Rectangle(new Point(0, 0), MasterSize), ImageLockMode.ReadOnly, WfPixelFormat.Format32bppArgb);
    GL.BindTexture(TextureTarget.Texture3D, Id);
    GL.TexSubImage3D(TextureTarget.Texture3D, 0, 0, 0, 0, MasterSize.Width, MasterSize.Height, index, GlPixelFormat.Bgra, PixelType.UnsignedByte, thedata.Scan0);
    GL.BindTexture(TextureTarget.Texture3D, 0);
    bmp.UnlockBits(thedata);
}

MasterSize 与上一个问题中的 Size 相同,Id 是上一个问题中的 int texId

当我在着色器上渲染第 0 个纹理时(如前所示)并且 Replace index = 0 没有任何变化。但是,当我 Replaceindex = 1 并渲染第 0 个时,它会执行我期望 index = 0 执行的操作。

尽管有 3 个纹理,但在 index = 2 时出现内存损坏错误(但对于 -4 和 12 等荒谬的值则不会)。

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

我可以通过使用 00.51 访问所有 3 个纹理作为着色器上纹理的 Z,所以我知道它们在那里。

TexSubImage3D 的第 8 个参数是一个 int,因此它不需要范围为 0 到 1 的浮点数。

我做错了什么?

首先,你没有3个纹理。你有一个纹理,这是一个特定大小的三维纹理。

glTexSubImage3D 将像素数据的 3D 矩形体积上传到纹理。 SubImage 函数可以用像素数据覆盖纹理的任意部分,因此它有两组坐标。它在纹理中给出了一个开始写入的偏移量,以及要写入的体积的大小。

由于这是一个 3D 矩形体积,偏移量和大小由 3 个参数提供:3D 体积的 XYZ 偏移量,以及要覆盖的体积的 width/height/depth。请注意,尺寸是输入体积的 尺寸 ,而不是 3D 图像中的绝对位置。

您正在尝试将 3D 纹理视为许多 2D 切片1。好吧,2D 图像实际上只是深度为 1 的 3D 图像。这就是您要上传的内容。

那么……这么说。由于您提供的 3D 图像的深度为 1,因此 depth 参数应该是这样的。 Z 偏移指定要覆盖的 Z 图像。

你的函数调用应该是:

GL.TexSubImage3D(TextureTarget.Texture3D, 0, 0, 0, index, MasterSize.Width, MasterSize.Height, 1, GlPixelFormat.Bgra, PixelType.UnsignedByte, thedata.Scan0);

1:OpenGL 已经有办法做到这一点:2D array texture。这具有双重好处,即从不在阵列层之间混合,并且能够使用整数层索引而不是层的纹理坐标。但它没有改变关于你这里的问题,因为它也使用3D函数来访问纹理的存储。