我已经写了一个简单的程序,创建了一个正交透视图,并将包含PNG格式的纹理放在一个四边形上。然而,我无法弄清楚为什么一些颜色会显示混乱。
PNG文件看起来像这样(中间的白色矩形是透明的):
四边形在我的OpenGL程序中看起来像这样:
下面是初始化OpenGL的代码以及OpenGL线程调用的方法中发生的事情。我使用JOGL。
颜色仍然混乱,但这次混乱的方式不同: 如何确定我的png图像是哪种特定格式?
== 更新2 - 解决方案实现 ==
首先,我要感谢jcadam,rotoglup和Tim指导我走上了正确的方向。
简而言之,问题在于Java解码图像时像素的排序方式并不总是适合传递到OpenGL。更准确地说,如果您的图像中没有Alpha通道,则没问题,但如果您有alpha通道,则排序是错误的,一些颜色会混乱。
现在,我开始制作自己的手动实现,对于32位PNG和24位JPEG效果很好:
然而后来我发现JOGL有自己的助手工具,实际上我最终使用了它:
PNG文件看起来像这样(中间的白色矩形是透明的):
四边形在我的OpenGL程序中看起来像这样:
下面是初始化OpenGL的代码以及OpenGL线程调用的方法中发生的事情。我使用JOGL。
public void init(GLAutoDrawable gLDrawable) {
gl.glGenTextures(1, textureId, 0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureId[0]);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
BufferedImage image = null;
try {
image = ImageIO.read(new File("d:\\temp\\projects\\openglTest1\\texTest.png"));
} catch (IOException e1) {e1.printStackTrace();}
DataBufferByte dataBufferByte = (DataBufferByte) image.getRaster().getDataBuffer();
Buffer imageBuffer = ByteBuffer.wrap(dataBufferByte.getData());
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL2.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL2.GL_RGBA, GL.GL_UNSIGNED_BYTE, imageBuffer);
gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL2.GL_BLEND_SRC);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
}
//this is called by the OpenGL Thread
public void display(GLAutoDrawable gLDrawable) {
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY);
gl.glFrontFace(GL2.GL_CCW);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, textureBuffer);
gl.glDrawElements(GL.GL_TRIANGLES, indices.length, GL.GL_UNSIGNED_BYTE, indexBuffer);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
}
对我来说这很令人困惑,因为虽然我不是OpenGL专家,但在使用这些命令之前我尝试了解它们的作用。实际上,我在Android上也做了同样的事情,一切都正常显示,但是在Java中使用JOGL时,我得到了这里描述的结果。我唯一不同的地方是加载png图像的方式。在Adroid上有一个辅助方法,如下:
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapStatic, 0);
在使用JOGL时,我通过以下方式进行自己的加载:
try {
image = ImageIO.read(new File("d:\\temp\\projects\\openglTest1\\texTest.png"));
} catch (IOException e1) {e1.printStackTrace();}
DataBufferByte dataBufferByte = (DataBufferByte) image.getRaster().getDataBuffer();
Buffer imageBuffer = ByteBuffer.wrap(dataBufferByte.getData());
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL2.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL2.GL_RGBA, GL.GL_UNSIGNED_BYTE, imageBuffer);
如上所述。
==更新==
根据jcadam的评论,我已尝试将像素数据的格式设置为GL_BGRA:
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL2.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL2.GL_BGRA, GL.GL_UNSIGNED_BYTE, imageBuffer);
颜色仍然混乱,但这次混乱的方式不同: 如何确定我的png图像是哪种特定格式?
== 更新2 - 解决方案实现 ==
首先,我要感谢jcadam,rotoglup和Tim指导我走上了正确的方向。
简而言之,问题在于Java解码图像时像素的排序方式并不总是适合传递到OpenGL。更准确地说,如果您的图像中没有Alpha通道,则没问题,但如果您有alpha通道,则排序是错误的,一些颜色会混乱。
现在,我开始制作自己的手动实现,对于32位PNG和24位JPEG效果很好:
public void texImage2D(File imageLocation,GL gl) {
BufferedImage initialImage = null;
try {
initialImage = ImageIO.read(imageLocation);
} catch (IOException e1) {
throw new RuntimeException(e1.getMessage(), e1);
}
int imgHeight = initialImage.getHeight(null);
int imgWidth = initialImage.getWidth(null);
ColorModel cm = initialImage.getColorModel();
boolean hasAlpha = cm.hasAlpha();
Buffer buffer = null;
int openGlInternalFormat = -1;
int openGlImageFormat = -1;
if(!hasAlpha) {
DataBufferByte dataBufferByte = (DataBufferByte) initialImage.getRaster().getDataBuffer();
buffer = ByteBuffer.wrap(dataBufferByte.getData());
openGlInternalFormat = GL2.GL_RGB;
openGlImageFormat = GL2.GL_BGR;
} else {
openGlInternalFormat = GL2.GL_RGBA;
openGlImageFormat = GL2.GL_RGBA;
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, imgWidth, imgHeight, 4, null);
ComponentColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[] { 8, 8, 8, 8 },
true, false,
ComponentColorModel.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
BufferedImage bufImg = new BufferedImage(colorModel,
raster, false,
null);
Graphics2D g = bufImg.createGraphics();
g.drawImage(initialImage, null, null);
DataBufferByte imgBuf = (DataBufferByte) raster.getDataBuffer();
byte[] bytes = imgBuf.getData();
buffer = ByteBuffer.wrap(bytes);
g.dispose();
}
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, openGlInternalFormat, imgWidth, imgHeight, 0, openGlImageFormat, GL.GL_UNSIGNED_BYTE, buffer);
}
然而后来我发现JOGL有自己的助手工具,实际上我最终使用了它:
//this code should be called in init(), to load the texture:
InputStream stream = new FileInputStream("d:\\temp\\projects\\openglTest1\\texTest.png");
TextureData data = TextureIO.newTextureData(gl.getGLProfile(),stream, false, "png");
Texture myTexture = TextureIO.newTexture(data);
//this code should be called in the draw/display method, before the vertices drawing call
myTexture.enable(gl);
myTexture.bind(gl);