Упаковка float в vec4 - как работает этот код?
Я пытаюсь изучить теневое отображение в WebGL. Я вижу тот же фрагмент кода шейдера, который копируется в различных библиотеках и примерах, которые достигают этого. Однако нигде я не нашел объяснения, как это работает.
Идея состоит в том, чтобы сохранить значение глубины (один поплавок) в цветовой буфер (vec4). Существует функция пакета, которая сохраняет float в vec4 и распаковывает функцию, которая извлекает float из vec4.
vec4 pack_depth(const in float depth)
{
const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
vec4 res = fract(depth * bit_shift);
res -= res.xxyz * bit_mask;
return res;
}
float unpack_depth(const in vec4 rgba_depth)
{
const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
float depth = dot(rgba_depth, bit_shift);
return depth;
}
Я бы предположил, что упаковка float в vec4 должна быть тривиальной проблемой, просто скопируйте ее в один из 4 слотов vec4 и оставите других неиспользованными. Вот почему логика смещения битов в вышеприведенном коде меня озадачивает.
Может ли кто-нибудь пролить свет?
Ответы
Ответ 1
Он не хранит GLSL float
в GLSL vec4
. Что он делает, это сохранение значения в vec4
, которое при записи в фреймбуфер RGBA8 (32-битное значение) может быть прочитано как vec4
, а затем восстановлено в тот же float
, который был указан ранее.
Если вы делаете то, что вы предлагаете, просто записывая значение с плавающей запятой в красный канал фреймбуфера, вы получите только 8 бит точности. С помощью этого метода вы получаете все 32 бита для вас.
Ответ 2
В дополнение к приведенному выше ответу вам может быть интересен расширение текстуры с плавающей запятой, описанное здесь:
http://www.khronos.org/registry/webgl/extensions/OES_texture_float/
Обратите внимание, что существуют аппаратные/программные настройки там, где это расширение не существует/не выполняется, но если оно действительно является хорошим расширением. Мой опыт в том, что он тоже быстрый. Если вы используете это, вы можете использовать оставшиеся три канала для хранения другой информации, такой как цвет от проецируемой текстуры.
Ответ 3
Если вы заинтересованы в подробных подробностях о том, как работают эти процедуры, я предлагаю вам прочитать мой пост в блоге. Я добавляю некоторые подробности о том, как работает этот код, и рассмотрим некоторые возможные варианты использования.
Как вы, вероятно, выяснили, этот код кодирует нормированное значение float для vec4
. OpenGL ES 2.0 или WebGL (на момент написания) могли бы использовать эти программы pack/unpack для обеспечения 32-битных точных плавающих точек через текстуры RGBA8
(подробнее об этом в спецификации).
Даже с расширением, размещенным Mikael (OES_texture_float
), может потребоваться (для целей отладки, например) сбросить полные 32-битные точные нормализованные плавающие точки и, как описано в спецификации readPixels
, в настоящее время ограничено следующим
Принимаются только две комбинации формата и типа. Первый - формат RGBA и тип UNSIGNED_BYTE. Второй - формат, выбранный для реализации.