【问题标题】:OpenGL texture colors are wrongOpenGL纹理颜色错误
【发布时间】:2012-02-29 14:29:15
【问题描述】:

我制作了一个简单的程序,它创建一个正交透视图,并将一个包含 png 的纹理放在四边形上 但是,我不明白为什么有些颜色显示的很乱。

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 专家,但我在使用上述所有 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);

如上所述。

==更新==

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

【问题讨论】:

  • @jcadam 我已经更新了我的问题,我已经尝试过你所说的但我仍然得到一个(不同的)不好的结果
  • @jcadm:实际上,如果我在paint.net 中打开该 png 并将其保存为 jpg 格式,100% 质量,然后我使用 GL_BGR 加载它,它显示正常,所有颜色都是它们应该。只是为了png,它不起作用。

标签: opengl colors textures jogl


【解决方案1】:

对我来说它看起来像 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 通道无关紧要。

【讨论】:

  • 是的,你说得对,透明通道无关紧要。 Java 的图片格式对非 alpha 图像中的像素“字节”进行排序,其方式与 OpenGL 的 BGR 相同。当存在 Alpha 通道时,Java 的格式不再匹配任何 OpenGL 格式(例如 BGRA 或 RGBA)。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    只是快速搜索了一下(我对 Java ImageIO 没有任何实际经验),似乎 Java 有原生的 ARGB 字节排序,你可以看看这个source code 以获得灵感。

    【讨论】:

    • 是的,看起来像像素排序格式问题。 Java 的像素排序与 OpenGL 理解的任何格式都不匹配。我需要重新排序字节数组缓冲区中的像素,然后才能将它们传递给 OpenGL。
    • 多么奇怪。这对我来说是新的。我用过 OpenGL,也用过 Java。但绝不会同时 :)
    猜你喜欢
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多