Как сделать объект прозрачным opengl

Обновлено: 07.07.2024

у меня есть текстура OpenGL, которая привязана к простому квадроциклу.

моя проблема: моя текстура 128x128 пикселей изображения. Я заполняю только около 100x60 пикселей на этом изображении, другие пиксели прозрачны. Я спас его .PNG-файл. Когда я рисую, прозрачная часть связанной текстуры белая.

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

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

проверьте, что ваша текстура имеет формат RGBA, и включите смешивание и установите смешивание func:

и рисовать текстуры. Если ваша текстура не RGBA, тогда нет альфа-и смешивание ничего не сделает.

EDIT: поскольку вы опубликовали свой код, я могу обнаружить серьезную ошибку:

вы говорите GL, что текстура имеет internalFormat RGBA, но растровые данные имеют формат BGR, поэтому Альфа из ваших текстурных данных отсутствует. Это предполагает, Альфа = 1.0.

When I'm drawing, the transparent part of the binded texture is white.

это означает, что ваш PNG-парсер преобразовал прозрачные области в значение белого. Если вы хотите визуализировать прозрачные слои с помощью OpenGL, вы обычно не зависите от текстурных файлов для сохранения прозрачности, а вместо этого используете GLBlendFunc() . Более подробная информация здесь:

кроме того, если вы визуализируете буфер кадров и копируете результат в текстуру, убедитесь, что буфер кадров включен. Например, при использовании osgViewer это может быть достигнуто (сделайте это перед вызовом setUpViewInWindow):

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


В этом уроке мы собираем добавить поддержку текстур с прозрачностью.

Прозрачность может быть довольно раздражающей вещью в реализации.
Представьте, что мы находимся в процессе рендеринга сцены, мы отрисовали дом, местность и некоторые другие пейзажи.
И нужно визуализировать следующий объект со стеклом. OpenGL видит некоторую прозрачность и поэтому рассчитывает как смесь цвета стекла и цвета всего что стоит за ним, в зависимости насколько прозрачное стекло.
Но если мы продолжим визуализировать сцену с объектами, то могут появиться объекты которые после визуализации стекла будут за стеклом, то они уже не отобразятся на сцене. Цвет уже рассчитан и меняться не будет, иллюзия прозрачности нарушается.
Поэтому нужно отсортировывать все прозрачные объекты так, чтобы визуализация сцены от самого дальнего к ближнему была.

Работать с прозрачностью не очень весело, однако в некоторых случаях с которыми мы будем работать в этом уроке есть более простой способ. Когда объект имеет текстуру которая полностью прозрачная или непрозрачная в любой точке, например трава, листья папоротника.
Нужно сообщить OpenGL вообще не визуализировать прозрачные пиксели.
Давайте поправим класс игрового цикла (MainGameLoop) и посмотрим как выглядит данная визуализация без прозрачности. Загрузим перед игровым циклом наши модели травы и папоротников.
Запустим и посмотрим, что вышло. Выходит там где должна быть прозрачность, выходит черный цвет.


Давайте перейдем к фрагментному шейдеру и изменим концовку. Сделаем проверку, если пиксель имеет прозрачность больше 0.5, то пропускаем отрисовку пикселя.
Запустим и посмотрим результат.


Для этого в классе ModelTexture определим логическую переменную, имеет ли текстура модели прозрачность.
Перейдём в класс MasterRenderer, нам нужно создать методы включения и отключения отсечения граней.
А теперь в классе EntityRenderer в методе подготовки текстурированной модели к визуализации (prepareTexturedModel) добавим отключение отсечения граней если есть прозрачная текстура. И включим отсечение по-умолчанию после окончания визуализации каждой модели (метод unbindTexturedModel).
Давайте перейдем к основному игровому циклу и добавим прозрачность в текстурах некоторых.
Запустим и посмотрим, что теперь все отображается и можно видеть.


Теперь отображаются все стороны листов папоротника. Исключение это освещение на траве, потому что трава состоит из 2-ух прямоугольников. Нормали на прямоугольниках сталкиваются. Направлены друг к другу и поэтому освещение на них будет сильно отличаться. Поэтому придется подделать освещение на объекте. Установить все нормали, чтобы указывали вверх, что сделаем освещение более постоянное.


Перейдем в класс текстурной модели (ModelTexture) и добавим ещё один параметр использование фальшивого освещения (useFakeLighting) Далее перейдём в вершинный шейдер и добавим этот параметр туда юниформу фальшивого освещения. Если фальшивое, то направляем вектор нормали вверх по оси Y. Теперь перейдем в статический шейдер(StaticShader) и пропишем ввод новой юниформы. В классе EntityRenderer в методе prepareTexturedModel нужно загрузить данное значение юниформу. Теперь в главном игровом цикле добавим для травы фальшивое освещение. Запустим сейчас игру, теперь трава выглядит как нужно.

Альфа-смешивание можно включить, чтобы сделать поверхности прозрачными, например:

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

введите описание изображения здесь

Я не уверен, должен ли это быть ответом или нет, но ошибки в вашем изображении вызваны рендерингом без проверки глубины на всех примитивах. Вы должны визуализировать сцену в 2 прохода: сначала визуализируйте всю твердую геометрию. После этого отключите запись глубины (не GL_DEPTH_TEST) и визуализируйте полупрозрачную геометрию примерно в обратном порядке. Это гарантирует, что прозрачная геометрия не будет нарисована перед геометрией сплошной, которая перед ней.

@yuriks В данном случае это, вероятно, плохой пример с моей стороны, но все должно быть прозрачным. Я хотел что-то, чтобы показать, как неправильная прозрачность может выглядеть, когда сделано плохо. Также пример, где сортировка геометрии была бы удивительно трудной (например, здесь пол представляет собой один гигантский многоугольник и покрывает весь диапазон глубины).

Есть много методов OIT.

Другой набор техник - это смешанные OIT. Одним из последних и интересных является взвешенный смешанный OIT, предложенный McGuire и Bavoil . Это в основном применяет взвешенную сумму для всех поверхностей, которые занимают данный фрагмент. Предлагаемая ими схема взвешивания основана на пространстве камеры Z (в приближении к окклюзии) и непрозрачности.
Идея состоит в том, что, если вы можете свести проблему к взвешенной сумме, вас не волнует порядок.

Помимо оригинальной статьи, в блоге Мэтта Петтинео есть отличный ресурс для подробностей реализации и проблем, связанных с Weighted Blended OIT . Как вы можете прочитать из его поста, эта техника не является серебряной пулей. Основная проблема заключается в том, что схема взвешивания является центральной и должна быть настроена в соответствии с вашей сценой / контентом. Из его экспериментов, хотя техника, кажется, работает нормально для относительно низкой и средней непрозрачности, она терпит неудачу, когда непрозрачность приближается к 1, и поэтому не может быть использована из материалов, где большая часть поверхности непрозрачна (он приводит пример листвы).

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

Что касается того, что необходимо для взвешенного смешанного OIT, то ничего, кроме двух дополнительных целей рендеринга. Тот, который вы заполняете предварительно умноженным альфа-цветом (цвет * альфа) и альфа, оба взвешиваются соответственно. Другой только для весов.

Одним из вариантов является использование глубинного пилинга.

По сути, каждый обрабатывает сцену определенное количество раз (скажем, n раз), чтобы определить самые близкие, вторые самые близкие, вплоть до n самых близких фрагментов сцены.

Эта обработка выполняется путем применения обычного теста глубины ко всей сцене (который, естественно, возвращает ближайшую поверхность). Затем используется результат теста глубины, чтобы отфильтровать первый слой, игнорируя все с меньшей глубиной, чем возвращается в тесте глубины.

Повторное применение теста глубины вернет второй слой. Повторите по мере необходимости.

Когда у вас есть слои, вы можете просто нарисовать все слои в обратном порядке (при условии, что вы отслеживали цвета RGBA для каждого слоя), смешивая их в обычном порядке, так как слои расположены в порядке спереди назад.

Благодарность! Похоже, мне понадобятся два буфера глубины для этого. То есть один, чтобы сохранить и отфильтровать последние глубины, и один, чтобы сделать проверку глубины для текущего рендера. Поправьте меня, если я ошибаюсь, но я предполагаю, что мне понадобятся две текстуры глубины для FBO, которые я меняю между каждым проходом пилинга.

Не получается сделать объекты полупрозрачными. Есть прямоугольник, внутри него должен быть другой прямоугольник, использовав glBlendFunc стороны прямоугольника действительно становятся прозрачными, но находящийся внутри объект все равно не видно. Проверял с помощью glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); , объект точно находится внутри а не где-то за границами. Объекты рисуются с помощью массивов вершин. Полупрозрачность реализую так:

введите сюда описание изображения


Читайте также: