Неправильные цвета текстуры OpenGL - PullRequest
5 голосов
/ 29 февраля 2012

Я сделал простую программу, которая создает перспективу Орто и помещает текстуру, содержащую 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, и все отображается нормально, но когда я делаю это на 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);

как описано выше.

== 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. Точнее, если у вас нет альфа-канала на изображении, это нормально, но если у вас есть альфа-канал, порядок плохой, и некоторые цвета будут перемешаны.

Теперь я начал с собственной ручной реализации, которая хорошо работает для 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 ]

5 голосов
/ 29 февраля 2012

Похоже, 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 отключена, альфа-канал не имеет значения.

1 голос
/ 01 марта 2012

Просто из быстрого поиска (у меня нет никакого реального опыта работы с Java ImageIO), кажется, что у Java есть собственный порядок байтов ARGB, вы можете взглянуть на этот исходный код длявдохновение.

1 голос
/ 29 февраля 2012

Хмм ... Похоже, проблема формата пикселей. Вы можете получить более конкретную информацию и попробовать GL_RGBA8, GL_RGBA16 и т. Д. Является ли это 8-битным PNG, а не 24 или 32? Разве нет альфа-канала (в этом случае используйте GL_RGB, а не GL_RGBA)?

...