Хороший способ справиться с альфа-каналами в 8-битном растровом изображении? - OpenGL - С++

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

  1. получить значения прозрачности для каждого пикселя

и

  1. визуализировать их с примененной прозрачностью

У кого-нибудь есть хороший пример этого? Поддерживает ли это OpenGL?


person Flarmar Brunjd    schedule 20.06.2011    source источник


Ответы (2)


Прежде всего, как правило, лучше преобразовать растровые данные в 32-битные, чтобы каждый канал (R, G, B, A) получил 8 бит. При загрузке текстуры укажите 32-битный формат.

Затем при рендеринге вам нужно будет glEnable(GL_BLEND); и установить функцию смешивания, например: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);. Это говорит OpenGL смешивать RGB текстуры с цветом фона, используя альфа-канал вашей текстуры.

Если вы делаете это с 3D-объектами, вы также можете отключить отсечение задней грани (чтобы вы видели заднюю часть объекта через переднюю часть) и отсортировать треугольники задом наперед (чтобы смешение произошло). в правильном порядке).

Если исходное растровое изображение является 8-битным (т. е. используется палитра с одним цветом, указанным в качестве маски прозрачности), то, вероятно, проще всего преобразовать его в RGBA, установив альфа-значение равным 0, когда цвет соответствует вашей маске прозрачности.

Некоторые подсказки, чтобы вещи (возможно) выглядели лучше:

  • Ваш альфа-канал будет работать по принципу «все или ничего» (либо 0x00, либо 0xff), поэтому примените алгоритм размытия, чтобы получить более мягкие края, если это то, что вам нужно.
  • Для текселей (текстурных пикселей) с нулевым альфа-каналом (полностью прозрачный) замените цвет RGB ближайшим непрозрачным текселем. Когда координаты текстуры интерполируются, они не будут смешиваться с исходным цветом прозрачности из вашего BMP.
person geofftnz    schedule 20.06.2011
comment
@geofftnz Да. К сожалению, растровые изображения находятся в архивах, которые я не могу изменить, поэтому мне нужно будет работать с ними как в. Можете ли вы уточнить, что мне следует преобразовать в RGBA? Благодарю вас! - person Flarmar Brunjd; 20.06.2011
comment
вы говорите о файлах BMP? - person geofftnz; 20.06.2011
comment
Ага. 8-битные файлы bmp находятся в архивах, которые я не могу изменить, поэтому мне нужно загрузить их как есть. - person Flarmar Brunjd; 20.06.2011
comment
@geofftnz Извините, я запутался. В 8-битном растровом изображении, о котором вы упомянули, один цвет указан как карта прозрачности. Это относится ко всему изображению? Если это так, я мог бы просто получить это значение и указать его в каждой текстуре, когда я правильно отрисовываю ее? Теперь вопрос как его получить... - person Flarmar Brunjd; 20.06.2011
comment
@Flarmar Он не обязательно имел в виду, что вам нужно было конвертировать файлы. Если вы не можете преобразовать файлы, вам следует преобразовать данные во время загрузки. - person Nicol Bolas; 20.06.2011
comment
@Flarmar да, конвертировать во время загрузки. Из памяти BMP не поддерживают прозрачность, так что это зависит от приложения. Доступны следующие варианты: определенный индекс в палитре считается прозрачным (обычно либо 0, либо 255), или определенное значение RGB (пурпурный 0xff00ff кажется наиболее распространенным) указывает на прозрачность. - person geofftnz; 20.06.2011

Если ваше растровое изображение является 8-битным одноканальным, оно либо в градациях серого, либо использует палитру. Сначала вам нужно преобразовать данные растрового изображения в формат RGBA. Для этого вы выделяете достаточно большой буфер, чтобы вместить 4-канальную растровую карту размеров исходного файла. Затем для каждого пикселя растрового изображения используйте значение этого пикселя в качестве индекса в палитре (таблица поиска) и поместите это значение цвета в соответствующий пиксель в буфере RGBA. После завершения загрузите в OpenGL с помощью glTexImage2D.

Если ваш графический процессор поддерживает фрагментные шейдеры (весьма вероятно), вы можете выполнить это преобразование LUT в шейдере: загрузите 8-битный пиксель как 2D-текстуру GL_RED или GL_LUMINANCE. И загрузите палитру как текстуру 1D GL_RGBA. Затем во фрагментном шейдере:

uniform sampler2D texture;
uniform sampler1D palette_lut;

void main()
{
    float palette_index = texture2D(texture,gl_TexCoord[0].st).r;
    vec4 color = texture1D(palette_lut, palette_index);
    gl_FragColor = color;
}

Смешанный рендеринг конфликтует с алгоритмом Z-буфера, поэтому вы должны отсортировать свою геометрию в обратном порядке, чтобы все выглядело правильно. Пока это влияет на объекты в целом, это довольно просто, но становится утомительным, если вам нужно отсортировать грани меша, рендерящего каждый кадр. Чтобы избежать этого, разбивайте сетки на выпуклые подсетки (конечно, выпуклая сетка уже не может быть разбита дальше). Затем используйте следующий метод:

  • Включить отбраковку лиц
  • for convex_submesh in sorted(meshes, far to near):
    • set face culling to front faces (i.e. the backside gets rendered)
    • визуализировать convex_submesh
    • установить отсечение лиц на задние грани (т. е. рендерится передняя сторона)
    • визуализировать convex_submesh снова
person datenwolf    schedule 20.06.2011