I am trying to load an image as a texture for openGL using the LWJGL library. From what I found out so far, I need to pass the texture as a ByteBuffer to openGL. What I have right now is some code that correctly loads an image, and stores it in a BufferedImage object. The thing is, I have no clue how to get from a BufferedImage to a ByteBuffer that contains data in the right format for use with openGL (as input for the function GL11.glTexImage2D()). Help is greatly appreciated!
Here's a method from the Space Invaders example that does what you want. (I think)
/**
* 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;
}
I used the solution above by Ron but the colors of the image when applied as a texture were incorrect, which means, the accepted solution will probably not produce same results for all kinds of images.
Trying to fix the problem with the color, I tried to use the ColorModel
of the original BufferedImage
, which can be accessed by calling the BufferedImage#getColorModel
. But, it gave me an exception that the ColorModel
of the original image is incompatible with the WritableRaster
object.
I looked for a solution for this and I found this one. Instead of calling Raster.createInterleavedRaster
to create a WritableRaster
, I used ColorModel#createCompatibleWritableRaster
.
Hope this helps. Here's the code:
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;
}
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));
}
buffer.flip();
return buffer;
}
Worked for me.
We also can do it in 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);
}
The method given by @Displee , uses CPU time, If you just load texture once it is OK. If you update the texture every frame, you could use Shader, it use GPU and less time(1/4 time I tested on my PC)
来源:https://stackoverflow.com/questions/5194325/how-do-i-load-an-image-for-use-as-an-opengl-texture-with-lwjgl