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

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

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

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

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

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"; 

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

EDIT :: Вот метод 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), поэтому, если вы думаете, что что-то еще Я обязательно отправлю это для вас. Извините за все неприятности!

Solutions Collecting From Web of "OpenGL ES 2.0 PNG альфа-канал"

+ Изменить

  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, как только вы закончите.

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

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

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

РЕДАКТИРОВАТЬ:

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

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

Учитывая, что ваша текстура выходит черным, если вы делаете fragcolor = base.aaa, это означает, что ваши данные текстуры «плохие».

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

Чтобы упростить вашу жизнь, вместо того, чтобы копировать все и вручную, вы можете просто загрузить растровое изображение в обычном режиме и использовать помощник 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, если не предварительно умножить, и выполните рендеринг, вы должны получить желаемый результат.