OpenGL Alpha Blending для полной непрозрачности или прозрачности - PullRequest
0 голосов
/ 23 мая 2018

ОРИГИНАЛ:

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

Для контекста я использую 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, и искал другие причины, по которым я замечаю проблемы с производительностью, но даже если приведенный выше вызов функции приводит к совершенно неправильным цветам, он вызываетмоя анимация должна работать плавно даже в случае перевода hello-triangle + sin (time).

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

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 для смещений).Это может быть отдельным источником неэффективности.

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

// vertex

#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 texture

1 Ответ

0 голосов
/ 23 мая 2018

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

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

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

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

Если это так, то сначала давайте предположим, что ваши текстуры уже выдают либо 1.0, либо .0 дляальфа-значение.После того, как вы очистите буфер, ваш blend func должен быть 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твоя текстура.Интерполированные значения могут быть любой величины.

...