Запись в трафаретный буфер OpenGL

Я читал о буфере трафарета в OpenGL. Основная концепция имеет смысл; фрагмент рисуется только в том случае, если он удовлетворяет определенному условию после того, как он был побитовым AND со значением в буфере трафарета. Но я не понимаю, как на самом деле вы пишете в буфер трафарета. Есть ли здесь функция, которую я пропускаю?

PS Когда я говорю писать, я имею в виду указать конкретные значения в буфере трафарета.

3 ответа

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

Буфер трафарета теоретически является таким же буфером, как задний буфер и буфер глубины. В три из них записываются одновременно (если они включены). Вы можете включить / отключить запись в них при определенных вызовах:

  • glColorMask(красный, зеленый, синий, альфа) - для заднего буфера
  • glDepthMask(t/f) - для буфера глубины
  • glStencilMask(значение) - для буфера трафарета

Для буфера глубины и трафарета вы можете дополнительно включить / отключить с помощью:

  • glEnable / glDisable(GL_DEPTH_TEST)
  • glEnable / glDisable(GL_STENCIL_TEST)

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

glClearColor(0, 0, 0, 1);
glClearStencil(0);
glStencilMask(0xFF);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Do not draw any pixels on the back buffer
glEnable(GL_STENCIL_TEST); // Enables testing AND writing functionalities
glStencilFunc(GL_ALWAYS, 1, 0xFF); // Do not test the current value in the stencil buffer, always accept any value on there for drawing
glStencilMask(0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); // Make every test succeed

// ... here you render the part of the scene you want masked, this may be a simple triangle or square, or for example a monitor on a computer in your spaceship ...

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Make sure you will no longer (over)write stencil values, even if any test succeeds
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Make sure we draw on the backbuffer again.

glStencilFunc(GL_EQUAL, 1, 0xFF); // Now we will only draw pixels where the corresponding stencil buffer value equals 1

// ... here you render your image on the computer screen (or whatever) that should be limited by the previous geometry ...

glDisable(GL_STENCIL_TEST);

Обратите внимание, что я специально пропустил любой код глубины, чтобы убедиться, что он не имеет ничего общего с трафаретом. Если вы визуализируете 3D-геометрию, вам может потребоваться включить ее. Возможно, вам даже придется НЕ записывать значение трафарета, если проверка глубины не удалась.

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

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

Удачи всем, кому понадобилась эта информация!

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

Все три буфера расположены в памяти графического процессора, проблема в том, что буфер трафарета использовал оставшиеся 8 бит из буфера глубины 24 бита!

Вот почему вы должны что-то визуализировать, чтобы установить или перезаписать значения в 8-битном буфере трафарета (на самом деле область в буфере глубины)

Ди-джей

Я описал, как выполнить рендеринг в буфер трафарета, используя libGDX. Процесс применения маски в OpenGL одинаков независимо от версии или платформы OpenGL.

Как маскировка работает в OpenGL

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

Используя буфер глубины, вы можете применить маски следующим образом:

Инициализируйте и настройте глубинное тестирование

Начните с очистки буфера глубины и отключите рендеринг в буфер цвета:

glClearDepthf(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glColorMask(false, false, false, false);

Далее, укажите критерии для буфера, это говорит OpenGL, как выполнить рендеринг в буфер глубины для создания маски. Вы делаете это, позвонив glDepthFunc (должна ли замаскированная область быть областью сцены, где нарисована фигура, или что-то еще? для различных видов ввода в функцию глубины, см. раздел "Проверка глубины" этого сайта)

glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
// Your code to render the mask goes here

Создание маски

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

Включить цветной буфер, установить функцию глубины и визуализировать на сцену

Теперь вы настраиваете OpenGL для рендеринга в буфер цвета и применяете маску глубины следующим образом:

glColorMask(true, true, true, true);
glDepthMask(true);
glDepthFunc(GL_EQUAL);
// Your code to render the scene goes here

Поскольку у вас включен буфер глубины, каждый пиксель в окне просмотра будет иметь соответствующее значение 0 или 1. Теперь другая функция глубины применяется к соответствующему значению для каждого пикселя, и, если результат равен true, пиксель отображается на экране. Здесь выбор функции глубины определяет способ применения маски.

Отключить тестирование глубины

Чтобы снова разрешить нормальный рендеринг сцены, вы отключаете буфер глубины следующим образом:

glDisable(GL_DEPTH_TEST);
Другие вопросы по тегам