Continuation of this question I asked. In that question I show how I give 3 textures to opengl and render one of them. I'm trying to edit one of these textures without replacing them all using this code:
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 is the same Size
as it is in the previous question and Id is the int texId
from the previous question.
When I render the 0th texture on the shader (as shown previously) and Replace
index = 0
nothing changes. However when I Replace
with index = 1
and render the 0th, it does what I expected the index = 0
to do.
Despite having 3 textures, I get a memory corruption error when index = 2
(but not for absurd values like -4 and 12).
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
I can access all 3 textures by using 0
, 0.5
, and 1
for the texture's Z on the shader, so I know they're there.
The 8th parameter of TexSubImage3D is an int, so it's not expecting a float range 0 to 1.
What am I doing wrong?
First, you do not have 3 textures. You have one texture, which is a three-dimensional texture of some particular size.
glTexSubImage3D
uploads a 3D rectangular volume of pixel data to a texture. The SubImage
functions can overwrite arbitrary parts of a texture with pixel data, so it has two sets of coordinates. It is given an offset in the texture to start writing from, and the size of the volume to write.
Since this is a 3D rectangular volume, the offset and the size are provided by 3 parameters: an XYZ offset into the 3D volume, and the width/height/depth of the volume to overwrite. Note that the sizes are the sizes of the input volume, not absolute positions within the 3D image.
You are trying to treat a 3D texture as though it were a number of 2D slices1. Well, a 2D image is really just a 3D image with a depth of one. So that's what you are trying to upload.
So... say that. Since the depth of the 3D image you're providing is 1, that is what the depth
parameter should be. The Z offset specifies which Z image you want to overwrite.
Your function call ought to be:
GL.TexSubImage3D(TextureTarget.Texture3D, 0, 0, 0, index, MasterSize.Width, MasterSize.Height, 1, GlPixelFormat.Bgra, PixelType.UnsignedByte, thedata.Scan0);
1: OpenGL already has a way to do this: a 2D array texture. This has the dual benefits of never blending between array layers and being able to use integer layer indices instead of texture coordinates for the layers. But it changes nothing about your problem here, since it too uses the 3D
functions for accessing the texture's storage.