OpenGL - Как создать независимую прозрачность заказа?
Я работал над игровым движком в образовательных целях, и я столкнулся с этой проблемой, которую я не могу найти для ответа:
Альфа-канал работает только для объектов, которые уже были нарисованы до объекта, имеющего альфа-канал (например: в сцене с 3 объектами, скажем, кошка, собака и бутылка (прозрачная). И кошка, и собака находятся за бутылкой; собака вытягивается первой, бутылка - второй, кошка - третья. Из бутылки видна только собака).
Я использовал C++ для движка, Win32 API для редактора и GLSL для шейдинга:
// some code here
vec4 alpha = texture2D(diffuse, texCoord0).aaaa;
vec4 negalpha = alpha * vec4(-1,-1,-1,1) + vec4(1,1,1,0);
vec4 textureComponentAlpha = alpha*textureComponent+negalpha*vec4(1,1,1,0);//(texture2D ( diffuse, texCoord0 ) ).aaaa;
gl_FragColor = (textureComponentAlpha + vec4(additiveComponent.xyz, 0)) * vec4(lightingComponent.xyz, 1);
В C++:
glEnable(GL_ALPHA_TEST);
glDepthFunc(GL_EQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Я предполагаю, что это как-то связано с тем, как устроен альфа-тест, или что-то в этом роде.
Может ли кто-нибудь помочь мне исправить это, пожалуйста?
4 ответа
Я использую что-то похожее на этот ответ, связанный комментарием @RetoKoradi, но я получил двухслойные прозрачные модели с текстурами (стекло как с внутренней, так и с внешней поверхностью) с полностью твердым механизмом и всем остальным.
Для таких сцен я использую также многопроходный подход, а Z-сортировка выполняется с помощью последовательности установки лицевой стороны.
- визуализировать все твердые объекты
визуализировать все прозрачные объекты
Это сложная часть сначала я установил
glGetIntegerv(GL_DEPTH_FUNC,&depth_funct); glDepthFunc(GL_ALWAYS); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_CULL_FACE);
Я получил слои геометрии, которые хранятся отдельно (внутренняя внешняя), поэтому Z-сортировка выполняется следующим образом:
- Рендеринг внешнего слоя задних граней с
glFrontFace(GL_CW);
- Рендеринг внутреннего слоя задних граней с
glFrontFace(GL_CW);
- Визуализация внутренних граней внутреннего слоя
glFrontFace(GL_CCW);
- Визуализируйте внешние грани переднего слоя с помощью
glFrontFace(GL_CCW);
И, наконец, восстановить
glDisable(GL_BLEND); glDepthFunc(depth_funct);
- Рендеринг внешнего слоя задних граней с
снова визуализировать все твердые объекты
Это далеко от совершенства, но достаточно для моих целей это выглядит так:
Я не могу подбодрить вас достаточно, чтобы взглянуть на этот документ NVidia и на соответствующий пост в блоге Morgan McGuire.
Это довольно легко реализовать и в целом дает отличные результаты.
Я не совсем уверен, что это поможет вашей ситуации, но у вас есть смешивание и альфа включены? Как в:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Метод получения правильной прозрачности визуализируемых объектов независимо от порядка их рисования называется Order Independent Transparency (OIT).
Есть отличная презентация от Nvidia, обобщающая последние решения в этой области: Order Independent Transparency In OpenGL 4.x.
«OpenGL 4.x» в названии не случайно, так как только в ядре OpenGL 4.2 появляются Atomic Counters, важные для реализации OIT.
Один из алгоритмов ОИТ выглядит следующим образом:
- Во время первого прохода рендеринга сохраните каждый фрагмент в буфере и соберите все фрагменты для одного пикселя экрана в связанный список. Атомарные счетчики используются как для хранения новых фрагментов в буфере, так и для поддержания связанного списка в каждом пикселе экрана.
- Во время второго прохода рендеринга каждый связанный список сортируется по z-глубине, а фрагменты смешиваются по альфа-каналу в правильном порядке.
Простая альтернатива OIT — отбрасывать каждый второй (нечетный) фрагмент во фрагментном шейдере:
if (onlyOddFragments && ((int(gl_FragCoord.x) + int(gl_FragCoord.y)) % 2) == 1)
discard;
Так вы увидите предметы, находящиеся дальше от камеры, в отброшенных фрагментах. Если включено мультисемпловое сглаживание (MSAA), то шаблон шахматной доски не виден даже в самом низком разрешении.
Вот видео , сравнивающее стандартный подход к прозрачности, когда все треугольники выводятся просто по порядку, а также два вышеприведенных подхода. Реализацию можно найти в некоторых проектах GitHub с открытым исходным кодом, например здесь .