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-сортировка выполняется с помощью последовательности установки лицевой стороны.

  1. визуализировать все твердые объекты
  2. визуализировать все прозрачные объекты

    Это сложная часть сначала я установил

    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);
    
  3. снова визуализировать все твердые объекты

Это далеко от совершенства, но достаточно для моих целей это выглядит так:

пример

Я не могу подбодрить вас достаточно, чтобы взглянуть на этот документ 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.

Один из алгоритмов ОИТ выглядит следующим образом:

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

Простая альтернатива OIT — отбрасывать каждый второй (нечетный) фрагмент во фрагментном шейдере:

          if (onlyOddFragments && ((int(gl_FragCoord.x) + int(gl_FragCoord.y)) % 2) == 1)
      discard;

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

Вот видео , сравнивающее стандартный подход к прозрачности, когда все треугольники выводятся просто по порядку, а также два вышеприведенных подхода. Реализацию можно найти в некоторых проектах GitHub с открытым исходным кодом, например здесь .

Другие вопросы по тегам