альфа-смешивание openGL для полной непрозрачности или прозрачности

ОРИГИНАЛ:

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

Для контекста я использую openGL 3.3 на старом компьютере Apple Mac и пытаюсь визуализировать перекрывающиеся слои четырехугольников. Каждый четырехугольник отображается на кусок текстуры png 4096 x 4096, который имеет области полной прозрачности.

Я хочу использовать альфа-смешивание, чтобы прозрачные части слоя N открывали непрозрачные части слоя N-1 (позади него). Поскольку мне не нужна полупрозрачность, я хотел бы знать - есть ли способ настроить glBlendFuncSeparate так, чтобы цвет фрагмента был просто самым непрозрачным текселем на переднем плане - дополнительное умножение не требуется?

Я пробовал что-то вроде этого:

glBlendFuncSeparate(GL_SRC_COLOR, GL_DST_COLOR, GL_ONE, GL_ZERO);

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

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

Я бы опубликовал часть своего кода, но он в основном состоит из настройки буферов вершин и объявлений больших статических массивов для тестирования. Мои шейдеры в основном сквозные: (например, основная функция в моем фрагментном шейдере :)

void main(void)
{
    vec4 texel = texture(tex0, v_uv);

    color = vec4(texel.rgb, texel.a);
}

и текстуры загружаются правильно. Я настроил рендеринг сзади наперед.

Как мне настроить такой рендеринг?

Заранее спасибо.

ОБНОВЛЕНИЕ:

Я пытался:

glEnable(GL_BLEND); 
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);

но появляется только передний слой с непрозрачным белым для его прозрачности. Я проверил значения RGBA, и похоже, что прозрачные секции имеют размер [1.0, 1.0, 1.0, 0.0], поэтому похоже, что мне нужно игнорировать цвет, когда альфа равен 0.0, даже если цвет не [0.0, 0.0, 0.0, а]. Чтобы смоделировать это, я добавил оператор if (alpha is 0.0), then discard;, но затем задержка вернулась.

Значит, функции не совсем правильные, или что-то еще не так.

Для получения дополнительной информации о моей настройке:

(Свою большую текстуру выложил внизу)

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

Полный фрагментный и вершинный шейдеры:

// вершина

#version 330 core
precision highp float;

layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_uv;

out vec2 v_uv;

uniform mat4 u_matrix;
uniform float u_aspect;
uniform vec3 u_position_cam;

uniform int u_count_layers;

void main(void) 
{
    // scroll speed depends on the inverse of the z position
    float speed_factor = (1.0 / pow(2.0, u_count_layers - a_position.z));

    // x offset
    float X = -u_position_cam.x * speed_factor;

    // make sure the bg quad jumps back to the correct position
    X = mod(X, (u_aspect) * 2.0);
    X += a_position.x;

    // y offset 
    float Y = -clamp(u_position_cam.y, 0.0, 2.0) * speed_factor;
    Y += a_position.y;

    gl_Position = u_matrix * vec4(X, Y, a_position.z, 1.0);

    v_uv = a_uv;
}

// фрагмент

#version 330 core
precision highp float;

in vec2 v_uv;

uniform sampler2D tex0;

out vec4 color;

void main(void)
{
    vec4 texel = texture(tex0, v_uv);

    color = vec4(texel);
}

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

Подумайте о цифрах - каждая секция текстуры покрывает 1280 x 720 пикселей. Всего 5 слоев по 3 четверки в каждом. Для каждого пикселя я проделываю одну и ту же работу N слоев раз, так что 4 608 000? Думаю, это может быть слишком дорого. Я также делаю странные арифметические операции по модулю и смещения. Если способ, которым я пытаюсь добиться прокрутки с параллаксом, слишком неуклюж, то как это можно сделать эффективно? Я готов изменить свой алгоритм / настройку, если определенно есть лучший способ сделать это. Мне любопытно, как правильно настроить текстуры и прозрачные слои, чтобы избежать проблем, с которыми я сталкиваюсь.

Мысль: а что если рендерить спереди назад? Как бы изменились функции наложения? (Я знаю, что вы обычно визуализируете прозрачные объекты сзади наперед, но здесь мне просто нужно перестать проверять слои, как только я выберу один с альфа == 1.0).

Атлас текстур 4096x4096 bg


person synchronizer    schedule 23.05.2018    source источник


Ответы (1)


Этот ваш вопрос чрезвычайно сложен для понимания, но, похоже, ключ кроется в

цвет фрагмента - это просто самый передний непрозрачный тексель - дополнительное умножение не требуется

Так вы говорите, что просто хотите нарисовать те пиксели, у которых альфа равна 1.0, а остальные отброшены? Как и в следующем примере:

Вы рисуете 3 текстуры размером 3x1. У первой текстуры все 3 пикселя непрозрачны; второй имеет непрозрачные первые 2 пикселя, а последний - непрозрачный только первый пиксель. Теперь результат должен быть таким, что первый пиксель взят из текстуры 3, второй - из 2, а третий - из 1.

Если это правда, то сначала предположим, что ваши текстуры уже выводят 1.0 или .0 для значения альфа. После очистки буфера ваша функция смешивания должна быть GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA для цветов. Это означает, что приближающийся цвет будет умножен на исходный альфа-канал и смешан с текущим цветом:

  • Для альфа 1.0 это означает, что исходный цвет будет полностью использован (умножен на 1.0), а целевой цвет полностью проигнорирован (умножен на 0.0) destination = source*1.0 + destination*.0. В просторечии этот пиксель будет полностью перерисован новым цветом.
  • Для альфа .0 это означает, что исходный цвет будет полностью проигнорирован (умножен на .0), а целевой цвет будет полностью использован (умножен на 1.0) destination = source*0.0 + destination*1.0. В обычном языке этот пиксель будет полностью сохранен, а новый цвет будет проигнорирован.

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

Если вам нужно дополнительно определить «непрозрачность», вы можете управлять этим в шейдере. Может применяться некоторый порог, например:

void main(void)
{
    vec4 texel = texture(tex0, v_uv);
    color = vec4(texel.rgb, step(texel.a, 0.5));
}

Обратите внимание, что даже если ваша входная текстура имеет только значения 0.0 и 1.0, это может быть не так в вашем шейдере, если вы не используете фильтр nearest для своей текстуры. Интерполированные значения могут иметь любую величину.

person Matic Oblak    schedule 23.05.2018
comment
Прошу прощения, если я немного не понял. Я добавил подробности к своему первоначальному вопросу. - person synchronizer; 23.05.2018