正确使用 GLTexImage3D 的问题
Problems using GLTexImage3D correctly
这就是我将位图提供给 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;
}
我找到了有关如何组织数据的描述 here,我将其解释为图像应垂直排列,并可能翻转或其他方式排列。
所以为了我的测试,我使用了 2 个图像,在片段着色器上,我像这样应用纹理:
void main()
{
outputColor = texture3D(ThreeDTexture,vec3(texcoord.x, 1.0 - texcoord.y, 0));
}
结果是两张图片按大致相等的比例合并。如果我将 vec3.z
参数设置为 0.5
,这就是我所期望的。所以我尝试了三张图片。它给出了提供的第一张和最后一张图像的 50-50 组合(?!?!)。这是它的行为,不考虑我给 vec3.z
.
的值
我希望该参数是所提供图像的 Z 轴。或者,如果我使用整数作为所提供图像数组的索引。
编辑:它是索引,但投影在 0 到 1 的范围内,就像 x、y 坐标一样。
我哪里错了?
我给 OpenGL 的东西(按顺序):
结果:
编辑: 正如 Rabbid76 解释的那样,解决方案是在调用 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);
纹理环绕参数 GL_TEXTURE_WRAP_S
、GL_TEXTURE_WRAP_T
和 GL_TEXTURE_WRAP_R
默认为 GL_REPEAT
。
缩小函数(GL_TEXTURE_MIN_FILTER
)和放大函数(GL_TEXTURE_MAG_FILTER
)的默认参数分别是GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR
.
参见 glTexParameter
。
"REPEAT" 和 "LINEAR" 的组合导致第一个体素与行、列或深度层的最后一个体素混合(插值),如果纹理坐标传递给查找函数的参数是 0.0.
如果你使用包裹参数GL_CLAMP_TO_EDGE
,那么第一个和最后一个体素不会混合,因为纹理坐标被限制了。
注意第一个体素(或纹素)的纹理坐标是1/(2*N)
,最后一个体素的坐标是1 - 1/(2*N)
,其中N
是一个体素的数量行、列或层。因此,坐标 0.0 正好位于第一个和最后一个体素的中间。 GL_REPEAT
会将坐标 0.0 固定到 1/(2*N)
。
这就是我将位图提供给 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;
}
我找到了有关如何组织数据的描述 here,我将其解释为图像应垂直排列,并可能翻转或其他方式排列。
所以为了我的测试,我使用了 2 个图像,在片段着色器上,我像这样应用纹理:
void main()
{
outputColor = texture3D(ThreeDTexture,vec3(texcoord.x, 1.0 - texcoord.y, 0));
}
结果是两张图片按大致相等的比例合并。如果我将 vec3.z
参数设置为 0.5
,这就是我所期望的。所以我尝试了三张图片。它给出了提供的第一张和最后一张图像的 50-50 组合(?!?!)。这是它的行为,不考虑我给 vec3.z
.
我希望该参数是所提供图像的 Z 轴。或者,如果我使用整数作为所提供图像数组的索引。
编辑:它是索引,但投影在 0 到 1 的范围内,就像 x、y 坐标一样。
我哪里错了?
我给 OpenGL 的东西(按顺序):
结果:
编辑: 正如 Rabbid76 解释的那样,解决方案是在调用 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);
纹理环绕参数 GL_TEXTURE_WRAP_S
、GL_TEXTURE_WRAP_T
和 GL_TEXTURE_WRAP_R
默认为 GL_REPEAT
。
缩小函数(GL_TEXTURE_MIN_FILTER
)和放大函数(GL_TEXTURE_MAG_FILTER
)的默认参数分别是GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR
.
参见 glTexParameter
。
"REPEAT" 和 "LINEAR" 的组合导致第一个体素与行、列或深度层的最后一个体素混合(插值),如果纹理坐标传递给查找函数的参数是 0.0.
如果你使用包裹参数GL_CLAMP_TO_EDGE
,那么第一个和最后一个体素不会混合,因为纹理坐标被限制了。
注意第一个体素(或纹素)的纹理坐标是1/(2*N)
,最后一个体素的坐标是1 - 1/(2*N)
,其中N
是一个体素的数量行、列或层。因此,坐标 0.0 正好位于第一个和最后一个体素的中间。 GL_REPEAT
会将坐标 0.0 固定到 1/(2*N)
。