问题
This is how I give the Bitmaps to OpenGL. (C#)
public static int Generate3DTexture( string[] names ) // file paths
{
//basically merging the images into one vertical column of images
MagickImageCollection allimages = new MagickImageCollection();
foreach (string eachname in names)
allimages.Add(new MagickImage(eachname));
MagickImage template = new MagickImage(MagickColor.FromRgba(0, 0, 0, 0), MasterSize.Width, MasterSize.Height * names.Length);
Point drawpnt = new Point(0, 0);
foreach (MagickImage each in allimages)
{
template.Composite(each, drawpnt.X, drawpnt.Y, CompositeOperator.Overlay);
drawpnt.Y += each.Height;
}
Bitmap merged = template.ToBitmap();
//saving the bitmap here is confirmed to stack them vertically
BitmapData thedata = merged.LockBits(new Rectangle(new Point(0, 0), merged.Size), ImageLockMode.ReadOnly, WfPixelFormat.Format32bppArgb);
int texId = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture3D, texId);
GL.TexImage3D(TextureTarget.Texture3D, 0, PixelInternalFormat.Rgba, MasterSize.Width, MasterSize.Height, names.Length, 0, GlPixelFormat.Bgra, PixelType.UnsignedByte, thedata.Scan0);
GL.GenerateMipmap(GenerateMipmapTarget.Texture3D);
GL.BindTexture(TextureTarget.Texture3D, 0);
merged.UnlockBits(thedata);
return texId;
}
I found a description for how the data should be organized here, which I interpreted to mean the images should be arranged vertically, and possibly flipped or something.
So for my test I used 2 images, on the fragment shader I apply the texture like so:
void main()
{
outputColor = texture3D(ThreeDTexture,vec3(texcoord.x, 1.0 - texcoord.y, 0));
}
The result is the two images merged in roughly equal proportions. That's what I would expect if I made the vec3.z
parameter 0.5
. So I tried it with three images. It gives a 50-50 combination of the first and last images supplied (?!?!). This is it's behavior without regard to the value I give for vec3.z
.
I expected that parameter to be the Z axis for the images supplied. Or if I used whole numbers for it to be an index for the array of images supplied.
EDIT: It is the index, but projected on the range 0 through 1, like the x,y coordinates are.
Where did I go wrong?
What I'm giving to OpenGL (in order):
The result:
EDIT: As Rabbid76 explains, the solution was to insert this after the call to GL.TexImage3D
:
GL.TexParameter(TextureTarget.Texture3D, TextureParameterName.TextureWrapS, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.Texture3D, TextureParameterName.TextureWrapT, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.Texture3D, TextureParameterName.TextureWrapR, (int)TextureParameterName.ClampToEdge);
回答1:
The texture wrap parameters GL_TEXTURE_WRAP_S
, GL_TEXTURE_WRAP_T
and GL_TEXTURE_WRAP_R
are by default GL_REPEAT
.
The default parameters for the minifying function (GL_TEXTURE_MIN_FILTER
) and magnification function are (GL_TEXTURE_MAG_FILTER
) are GL_NEAREST_MIPMAP_LINEAR
respectively GL_LINEAR
.
See glTexParameter.
The combination of "REPEAT" and "LINEAR" causes, that the first voxel is mixed (interpolated) with the last voxel of a row, column, or depth-layer, if the the texture coordinate parameters, which is passed to the lookup function, is 0.0.
If you would use the wrap parameter GL_CLAMP_TO_EDGE
, then the first and the last voxel won't become mixed, because the texture coordinate is clamped.
Note the texture coordinate of the first voxel (or texel) is 1/(2*N)
and the coordinate of the last voxel is 1 - 1/(2*N)
, where N
is the number of voxels in a row, column or layer. Because of that the coordinate 0.0, is exactly in the middle of the first and the last voxel. GL_REPEAT
would clamp the coordinate 0.0 to 1/(2*N)
.
来源:https://stackoverflow.com/questions/52326761/problems-using-glteximage3d-correctly