Как мне совместно использовать глубинное тестирование и прозрачность текстур в мире 2.5D?

11

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

Я делаю "2.5D" изометрическую игру с использованием OpenGL ES (JOGL). Под «2.5D» я подразумеваю, что мир трехмерен, но он визуализируется с использованием 2D-изометрических плиток.

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

Однако я столкнулся с проблемой. Если вы используете GL_DEPTH_TESTи GL_BLENDвместе, это создает эффект, когда объекты смешиваются с фоном, прежде чем они будут «отсортированы» по z-порядку (это означает, что вы получаете странный вид перекрытия, где должна быть прозрачность).

проблема перекрытия прозрачности

Вот некоторый псевдокод, который должен проиллюстрировать проблему (кстати, я использую libgdx для Android).

create() {
    // ...
    // some other code here
    // ...

    Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
    Gdx.gl.glEnable(GL10.GL_BLEND);
}

render() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    Gdx.gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

    // ...
    // bind texture and create vertices
    // ...
}

Итак, вопрос: как мне решить проблему перекрытия прозрачности?

Ник Болтон
источник
2
Просто комментарий, чтобы сказать вам, что я поступил точно так же, как и вы, для моего 2D движка: сначала пытался быть умным и сам Z-сортировать плитки, потом понял, что не было никакой причины, чтобы сцена была плоской, таким образом, давая моим плиткам Координата Z и активация альфа-теста. Не уверен, что вы правы, но вы не одиноки :-)
Сэм Хочевар

Ответы:

7

Итак, вот мое решение (пожалуйста, прокомментируйте, если это можно сделать лучше) ...

Оказывается, я должен был использовать альфа-тестирование (хотя я обнаружил это случайно, поэтому я не совсем уверен, почему это работает).

create() {
    // ...
    // some other code here
    // ...

    Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
    Gdx.gl.glEnable(GL10.GL_ALPHA_TEST);
}

render() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    Gdx.gl10.glAlphaFunc(GL10.GL_GREATER, 0);

    // ...
    // bind texture and create vertices
    // ...
}

Обратите внимание на использование GL_ALPHA_TESTи glAlphaFunc.

Ник Болтон
источник
Это тоже решило мою проблему. Спасибо, что поделился. Вы великолепны
Mathlover
2

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

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

Лютер
источник
1
Я думаю, что рисовать вещи от начала до конца легко в 2D-игре изо, только когда у вас фиксированная плоскость Y, и дизайнер полностью контролирует мир. Однако, когда материал может существовать где-либо в трехмерном пространстве, и вы позволяете пользователю изменять материал, это становится более сложным. Я думаю, что использование буфера глубины сделает мою жизнь намного проще.
Ник Болтон