OpenGL纹理颜色是错误的

时间:2012-02-29 14:29:15

标签: opengl colors textures jogl

我制作了一个简单的程序,可以创建一个Ortho透视图,并在四边形上放置一个包含png的纹理 但是,我无法弄清楚为什么有些颜色显示都是混乱的。

png看起来像这样(中间的白色矩形是透明的):

enter image description here

我的OpenGL程序中的四边形如下所示:

enter image description here

下面是初始化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专家,但我试图在使用它们之前了解上述所有OpenGL命令的作用。事实上,我在Android上不一样,所有内容都显示正常,但是当使用JOGL在Java中进行时,我得到了这里描述的结果。我唯一不同的是我加载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);

如上所述。

== UPDATE ==

根据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);

颜色仍然混乱,但这次是一个不同的混乱:

enter image description here

如何找出我的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);

3 个答案:

答案 0 :(得分:5)

对我来说看起来像ABGR。如果你只看颜色:

png red       (A1,B0,G0,R1)  looks like
opengl red    (R1,G0,B0,A1)

png bluegreen (A1, B1, G1, R0)  looks like 
opengl white  (R1, G1, B1, A0)

png blue      (A1, B1, G0, R0)  looks like 
opengl yellow (R1, G1, B0, A0)

png clear     (A0, B?, G?, R?)  could be
ogl bluegreen (R0, B?, G?, A?)

如果禁用了opengl透明度,则alpha通道无关紧要。

答案 1 :(得分:1)

嗯......它看起来像像素格式问题。您可以更具体,并尝试GL_RGBA8,GL_RGBA16等。这是一个8位PNG而不是24或32?是否没有alpha通道(在这种情况下使用GL_RGB而不是GL_RGBA)?

答案 2 :(得分:1)

刚刚快速搜索(我对Java ImageIO没有任何实际经验),似乎Java有一个原生的ARGB字节顺序,你可以看一下这个source code的灵感。 / p>