Могу ли я поставить R8G8B8A8 в UBO и использовать его как vec4?

Я пытаюсь оптимизировать работающий вычислительный шейдер. Его цель — создать изображение: найти подходящий цвет (используя небольшую палитру) и вызвать imageStore(image, ivec2, vec4).

  • Цвета индексируются в массиве uint в UniformBuffer.
  • Один цвет в этом UBO упакован внутри одного uint, как {0-255, 0-255, 0-255, 0-255}.

Вот код:

struct Entry
{
    *some other data*
    uint rgb;
};

layout(binding = 0) uniform SConfiguration
{
    Entry materials[MATERIAL_COUNT];
} configuration;

void main()
{
    Entry material = configuration.materials[currentMaterialId];

    float r = (material.rgb >> 16) / 255.;
    float g = ((material.rgb & G_MASK) >> 8) / 255.;
    float b = (material.rgb & B_MASK) / 255.;

    imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(r, g, b, 0.0));
}

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

  • Можно ли напрямую упаковать vec4(r, g, b, 0.0) внутри UBO, используя 4 байта (например, R8G8B8A8)?

person Ealrann    schedule 02.05.2019    source источник
comment
Не имеет отношения к исходному вопросу, но зачем вам здесь использовать imageStore()? Часто это медленнее и потребляет больше энергии, чем просто запись пикселя из фрагментного шейдера, и часто отключает такие оптимизации, как сжатие кадрового буфера. Не используйте его, если вам действительно это не нужно; для таких простых случаев, как этот, фрагментные шейдеры почти всегда являются лучшим решением.   -  person solidpixel    schedule 02.05.2019
comment
Я не использую вершины/фрагменты/растеризацию для основной платы (только для пользовательского интерфейса). Вот несколько картинок: github.com/Ealrann/VSand/blob/master/README. мд . Поэтому я подумал, что imageStore() — лучший вариант для меня, но я открыт для дополнительных мнений, потому что я все еще довольно новичок в мире рендеринга. Считаете ли вы, что это хороший вариант использования imageStore?   -  person Ealrann    schedule 02.05.2019


Ответы (2)


Можно ли это сделать напрямую? Нет.

Но в GLSL есть ряд функций для упаковки/распаковки нормализованных значений. В вашем случае вы можете передать значение как одно uint uniform, а затем использовать unpackUnorm4x8, чтобы преобразовать его в vec4. Итак, ваш код становится:

    vec4 color = unpackUnorm4x8(material.rgb);

Это, конечно, компромисс между памятью и производительностью. Поэтому, если память не является проблемой, вам, вероятно, следует просто передать vec4 (никогда не использовать vec3) напрямую.

person Nicol Bolas    schedule 02.05.2019
comment
Распаковка не всегда бесплатна, поэтому, если вам действительно не нужно экономить место, загрузите 4 поплавка. - person solidpixel; 02.05.2019

Можно ли напрямую упаковать vec4(r, g, b, 0.0) внутри UBO, используя 4 байта (например, R8G8B8A8)?

Невозможно выразить это напрямую как 4 однобайтовых значения; в шейдере нет подходящего типа данных, позволяющего объявить это как байтовый тип.

Однако, почему вы считаете, что вам это нужно? Просто загрузите его как 4 числа с плавающей запятой - это униформа, поэтому вы не будете копировать ее тысячи раз, поэтому дополнительный размер вряд ли будет проблемой на практике.

person solidpixel    schedule 02.05.2019
comment
На самом деле, когда писал вопрос, я думал так же. У меня не так много материалов, так что место не проблема, и этот буфер никогда не обновляется. Спасибо за ответ. - person Ealrann; 02.05.2019
comment
Уточненный ответ только для устранения двусмысленности в отношении использования термина «пакет», учитывая, что вы можете использовать распаковку в соответствии с ответом @Nicol Bolas выше. - person solidpixel; 03.05.2019