首页 > 解决方案 > 正确使用 GLTEXSubImage3D 的问题

问题描述

继续我问的这个问题。在那个问题中,我展示了如何为 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没有任何变化。但是,当我Replace使用index = 1并渲染第 0 个时,它会执行我期望的index = 0操作。

尽管有 3 个纹理,但当index = 2(但不是像 -4 和 12 这样的荒谬值)时出现内存损坏错误。

System.AccessViolationException: '试图读取或写入受保护的内存。这通常表明其他内存已损坏。

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

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

我究竟做错了什么?

标签: openglglslopentk

解决方案


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

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

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

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

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

你的函数调用应该是:

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

1:OpenGL 已经有办法做到这一点:二维数组纹理。这具有双重好处,即永远不会在数组层之间混合,并且能够使用整数层索引而不是层的纹理坐标。但它在这里没有改变您的问题,因为它也使用3D访问纹理存储的功能。


推荐阅读