我正在尝试使用LWJGL库加载一个图像作为OpenGL的纹理。根据我目前所发现的,我需要将纹理作为ByteBuffer传递给OpenGL。我现在拥有的是一些正确加载图像并将其存储在BufferedImage对象中的代码。问题是,我不知道如何从BufferedImage到ByteBuffer,后者包含用于OpenGL的正确格式的数据(作为函数GL11.glTexImage2D()的输入)。非常感谢您的帮助!
nr9pn0ug1#
这里有一个来自太空入侵者示例的方法,它可以做你想要的事情。(我想)
/** * Convert the buffered image to a texture */ private ByteBuffer convertImageData(BufferedImage bufferedImage) { ByteBuffer imageBuffer; WritableRaster raster; BufferedImage texImage; ColorModel glAlphaColorModel = new ComponentColorModel(ColorSpace .getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8, 8, 8 }, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, bufferedImage.getWidth(), bufferedImage.getHeight(), 4, null); texImage = new BufferedImage(glAlphaColorModel, raster, true, new Hashtable()); // copy the source image into the produced image Graphics g = texImage.getGraphics(); g.setColor(new Color(0f, 0f, 0f, 0f)); g.fillRect(0, 0, 256, 256); g.drawImage(bufferedImage, 0, 0, null); // build a byte buffer from the temporary image // that be used by OpenGL to produce a texture. byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()) .getData(); imageBuffer = ByteBuffer.allocateDirect(data.length); imageBuffer.order(ByteOrder.nativeOrder()); imageBuffer.put(data, 0, data.length); imageBuffer.flip(); return imageBuffer; }
yebdmbv42#
对于前面的答案,更直接的方法是使用image.getRGB进行颜色模型转换。以下摘录自getRGB上的Java 8文档:从图像数据的一部分返回默认RGB颜色模型(TYPE_INT_ARGB)和默认sRGB颜色空间中的整数像素数组。如果默认模型与图像ColorModel不匹配,则会进行颜色转换。使用这种方法时,返回的数据中每个颜色分量的精度只有8位。
image.getRGB
getRGB
TYPE_INT_ARGB
public static ByteBuffer imageToBuffer(BufferedImage image) { int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth()); ByteBuffer buffer = ByteBuffer.allocateDirect(pixels.length * 4); for (int pixel : pixels) { buffer.put((byte) ((pixel >> 16) & 0xFF)); buffer.put((byte) ((pixel >> 8) & 0xFF)); buffer.put((byte) (pixel & 0xFF)); buffer.put((byte) (pixel >> 24) & 0xFF); } buffer.flip(); return buffer; }
返回的缓冲区为GL_UNSIGNED_BYTE的GL_RGBA。
GL_UNSIGNED_BYTE
GL_RGBA
cnjp1d6j3#
我使用了Ron上面的解决方案,但图像作为纹理应用时的颜色不正确,这意味着,被接受的解决方案可能不会对所有类型的图像产生相同的结果。
为了解决颜色问题,我尝试使用原始BufferedImage的ColorModel,可以通过调用BufferedImage#getColorModel进行访问。但是,它给了我一个例外,原始图像的ColorModel与WritableRaster对象不兼容。
BufferedImage
ColorModel
BufferedImage#getColorModel
WritableRaster
我寻找了一个解决方案,但我找到了一个。我没有调用Raster.createInterleavedRaster来创建WritableRaster,而是使用了ColorModel#createCompatibleWritableRaster。
Raster.createInterleavedRaster
ColorModel#createCompatibleWritableRaster
希望这能帮上忙。代码如下:
public static ByteBuffer load(BufferedImage bufferedImage) { WritableRaster raster = bufferedImage.getColorModel().createCompatibleWritableRaster (bufferedImage.getWidth(), bufferedImage.getHeight()); BufferedImage textureImage = new BufferedImage(bufferedImage.getColorModel(), raster, true, new Hashtable<>()); Graphics graphics = textureImage.getGraphics(); graphics.setColor(new Color(0, 0, 0)); graphics.fillRect(0, 0, 256, 256); graphics.drawImage(bufferedImage, 0, 0, null); byte[] data = ((DataBufferByte) textureImage.getRaster().getDataBuffer()).getData(); ByteBuffer imageBuffer = ByteBuffer.allocate(data.length); imageBuffer.order(ByteOrder.nativeOrder()); imageBuffer.put(data, 0, data.length); imageBuffer.flip(); return imageBuffer; }
8zzbczxx4#
我们也可以在Shader中执行此操作。
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); DataBufferInt dbb = (DataBufferInt) image.getRaster().getDataBuffer(); glBindTexture(GL_TEXTURE_2D, id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,dbb.getData());
GL_Fragment_Shader:
# version 130 uniform sampler2D tex; in vec2 texCoordsVarying; out vec4 color; void main() { vec4 c2 = texture(tex, texCoordsVarying); color = vec4(c2.g, c2.b, c2.a, c2.r); }
@Displee给出的方法使用CPU时间,如果您只在纹理正常时加载纹理。如果你每一帧都更新纹理,你可以使用Shader,它使用GPU和更少的时间(我在我的PC上测试了1/4次)
4条答案
按热度按时间nr9pn0ug1#
这里有一个来自太空入侵者示例的方法,它可以做你想要的事情。(我想)
yebdmbv42#
对于前面的答案,更直接的方法是使用
image.getRGB
进行颜色模型转换。以下摘录自getRGB
上的Java 8文档:从图像数据的一部分返回默认RGB颜色模型(
TYPE_INT_ARGB
)和默认sRGB颜色空间中的整数像素数组。如果默认模型与图像ColorModel不匹配,则会进行颜色转换。使用这种方法时,返回的数据中每个颜色分量的精度只有8位。返回的缓冲区为
GL_UNSIGNED_BYTE
的GL_RGBA
。cnjp1d6j3#
我使用了Ron上面的解决方案,但图像作为纹理应用时的颜色不正确,这意味着,被接受的解决方案可能不会对所有类型的图像产生相同的结果。
为了解决颜色问题,我尝试使用原始
BufferedImage
的ColorModel
,可以通过调用BufferedImage#getColorModel
进行访问。但是,它给了我一个例外,原始图像的ColorModel
与WritableRaster
对象不兼容。我寻找了一个解决方案,但我找到了一个。我没有调用
Raster.createInterleavedRaster
来创建WritableRaster
,而是使用了ColorModel#createCompatibleWritableRaster
。希望这能帮上忙。代码如下:
8zzbczxx4#
我们也可以在Shader中执行此操作。
GL_Fragment_Shader:
@Displee给出的方法使用CPU时间,如果您只在纹理正常时加载纹理。如果你每一帧都更新纹理,你可以使用Shader,它使用GPU和更少的时间(我在我的PC上测试了1/4次)