OpenGL ES 2.0 PNG альфа-канал - PullRequest
       53

OpenGL ES 2.0 PNG альфа-канал

8 голосов
/ 17 августа 2011

Я только учусь работать с OpenGL ES 2.0 для Android. Я пытался просто отобразить текстуру в середине экрана, что было достаточно легко, но я не могу заставить работать альфа-версию PNG. Изображение будет отображаться с черным фоном, или все изображение будет слегка смешано с цветом фона, в зависимости от используемых настроек.

Реальные учебники, которым я следовал, чтобы достичь этой точки, никогда не работали с прозрачностью, поэтому я попытался поработать в коде, который нашел при поиске, и, вероятно, только что пропустил один важный шаг. Я искал довольно много, чтобы понять эту проблему, хотя, и я не видел ни одного ответа, который имел что-то, чего нет в моих настройках. Я попробовал каждую комбинацию glBlendFunc и что не без удачи.

Я подумал, что если бы я попытался вставить весь код, который может быть связан с этим, вопрос показался бы очень раздутым, поэтому я буду рад опубликовать любые фрагменты кода, которые вы, ребята, просите. Буду очень признателен за любые идеи о том, что я должен попробовать дальше.

РЕДАКТИРОВАТЬ :: Вот мой фрагментный шейдер, причина которого я считаю. Это единственная часть, в которой я никогда не находил достойного примера работы с прозрачностью, а все остальное соответствует тому, что я видел в других местах.

        final String fragmentShader =           
        "precision mediump float;       \n"  
        + "varying vec2 v_Color;          \n"     
        + "uniform sampler2D s_baseMap;   \n"
        + "void main()                    \n"     
        + "{                              \n"
        + "  vec4 baseColor;              \n"
        + "  baseColor = texture2D( s_baseMap, v_Color );   \n"
        + "   gl_FragColor = baseColor;     \n"    
        + "}                              \n"; 

Он никогда ничего не делает с альфой в явном виде, это из примера, который не использует его в конце концов, но я до сих пор не знаю много о фрагментных шейдерах, и потому что он, казалось, "вроде" работает, когда смешивается изображение на заднем плане, я подумал, что оно работает с альфа-версией в какой-то форме, и у меня просто что-то не так.

РЕДАКТИРОВАТЬ :: Вот метод "loadTexture". Это примерно то же самое, что и пример из книги openGL ES 2.0, из которого я пытаюсь извлечь уроки, с некоторыми изменениями, которые, кажется, приближают изображение к правильной работе.

    private int loadTexture ( InputStream is )
{
    int[] textureId = new int[1];
    Bitmap bitmap;
    bitmap = BitmapFactory.decodeStream(is);
    byte[] buffer = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];

    for ( int y = 0; y < bitmap.getHeight(); y++ )
        for ( int x = 0; x < bitmap.getWidth(); x++ )
        {
            int pixel = bitmap.getPixel(x, y);
            buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF);
            buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF);
            buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF);
        }

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bitmap.getWidth() * bitmap.getHeight() * 4);
    byteBuffer.put(buffer).position(0);

    GLES20.glGenTextures ( 1, textureId, 0 );
    GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] );

    GLES20.glTexImage2D ( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, 
                          GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuffer );

    GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
    GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
    GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
    GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE );

    return textureId[0];
}

Я понимаю, что делает код, но по общему признанию это все еще немного смущает меня, поэтому я могу просто упустить что-то очевидное из-за недостатка знаний.

Я не вижу никаких других частей моего кода, которые могли бы вызвать у меня проблемы, но программирование всегда полно неожиданностей (особенно в мире OpenGL, кажется), так что если вы думаете, что-то еще является причиной, я обязательно опубликую это и для вас. Извините за все проблемы!

Ответы [ 3 ]

9 голосов
/ 27 января 2012

Изменение

 for ( int y = 0; y < bitmap.getHeight(); y++ )
    for ( int x = 0; x < bitmap.getWidth(); x++ )
    {
        int pixel = bitmap.getPixel(x, y);
        buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF);
    }

в

 for ( int y = 0; y < bitmap.getHeight(); y++ )
    for ( int x = 0; x < bitmap.getWidth(); x++ )
    {
        int pixel = bitmap.getPixel(x, y);
        buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 3] = (byte)((pixel >> 24) & 0xFF);
    }

для включения альфа-информации, затем просто добавьте

GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glEnable(GLES20.GL_BLEND); 

прямо перед тем, как нарисовать текстуру. Не забудьте отключить GL_BLEND, как только вы закончите.

3 голосов
/ 17 августа 2011

Скорее всего, вы хотите использовать glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) в качестве функции наложения, и вам также необходимо записать альфа-значение текстуры в выходную переменную фрагментного шейдера gl_FragColor.

Чтобы все это работало, ваши загруженные данные текстуры должны содержать альфа-значение, и вы должны использовать формат текстуры, который поддерживает альфа-канал (RGBA, RGBA8 и т. Д.).

Вы можете проверить это, просто перенаправив альфа-значение на компоненты цвета RGB и проверив полученное изображение.

EDIT:

В коде загрузки вашего изображения вы забыли скопировать альфа-канал! Попробуйте предположить, что davebytes дает.

1 голос
/ 18 августа 2011

Ваш начальный шейдер в порядке.Альфа присуща цветным операциям, но может не применяться в зависимости от смешивания / режима / и т. д.

, учитывая, что ваша текстура получается черной, если вы выполняете fragcolor = base.aaa, что означает, что ваши данные текстуры 'плохо '.

смотря на загрузку вашей текстуры, да, это неправильно.Вы никогда не копируете альфу, только RGB.Предполагая, что java очищает байтовый массив до 0 с, вся альфа будет равна нулю, что приведет к черному ящику, что заставит изображение «исчезнуть», когда вы включите альфа-смешение.

Вместо этого, чтобы упростить вашу жизньиз всего ручного копирования и прочего, вы можете просто загрузить растровое изображение в обычном режиме и использовать помощник GLUtils для загрузки вместо непосредственного использования glTexImage2d:

  bitmap = BitmapFactory.decodeStream(is);  
  GLES20.glGenTextures ( 1, textureId, 0 );
  GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] );
  GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

Что-то в этом роде.Затем включите смешивание, используйте режим смешивания src + invsrc, если не было предварительно умножено, и выполните рендеринг, вы должны получить желаемый результат.

...