首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenGL纹理颜色错误

OpenGL纹理颜色错误
EN

Stack Overflow用户
提问于 2012-02-29 22:29:15
回答 3查看 6.9K关注 0票数 5

我做了一个简单的程序,创建了一个Ortho透视图,并在一个四边形上放置了一个包含png的纹理。然而,我不明白为什么有些颜色显示得乱七八糟。

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

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

下面是初始化OpenGL的代码,以及OpenGL线程调用的方法中发生的事情。我正在使用JOGL。

代码语言:javascript
复制
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上有一个助手方法,如下所示:

代码语言:javascript
复制
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapStatic, 0);

使用JOGL时,我通过以下方式进行自己的加载:

代码语言:javascript
复制
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,如下所示:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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有自己的辅助工具,这就是我最终使用的工具:

代码语言:javascript
复制
//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);
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-03-01 03:46:07

在我看来像是ABGR。如果你只看颜色:

代码语言:javascript
复制
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通道将无关紧要。

票数 5
EN

Stack Overflow用户

发布于 2012-02-29 22:41:54

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

票数 1
EN

Stack Overflow用户

发布于 2012-03-01 04:05:20

根据快速搜索(我没有任何使用Java的实际经验),看起来Java有一个原生的ARGB字节排序,您可以看看这个source code以获得灵感。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9500905

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档