Можно ли построить куб с менее чем 24 вершинами?

14

У меня есть мир на основе кубов, такой как Minecraft, и мне интересно, есть ли способ построить куб с менее чем 24 вершинами, чтобы я мог уменьшить использование памяти.

Это кажется мне невозможным по двум причинам: нормали не получатся правильными, а текстуры для лица не будут работать.

Это так или я не прав? Может быть, есть какая-нибудь необычная технология DX11, которая может помочь?

Изменить: просто чтобы уточнить, у меня есть 2 требования: мне нужно нормали поверхности для каждой грани куба, чтобы сделать правильное освещение, и мне нужен способ для адресации другого индекса в массиве текстуры для каждой грани куба

Telanor
источник
1
Вы хотите уменьшить использование памяти графической карты или RAM ?
двойник
1
Данные о вершинах хранятся в оперативной памяти и на графическом процессоре прямо сейчас, поэтому их уменьшение уменьшит и то, и другое.
Теланор

Ответы:

9

Если вам нужны только индивидуальные нормали, и если ваши текстовые координаты для лица строго 0/0, 0/1, 1/0, 1/1 (или похожи в соответствии с вашим макетом), то вы можете построить куб с 8 вершинами и 30 (полоса с перезапуском) или 36 (список) индексов. Извлеките нормали и текстовые координаты, используя поиск в массиве на основе SV_VertexID в вашем вершинном шейдере.

Это означает, что вам даже не нужно включать texcoords или нормали в ваш буфер вершин, что даст вам еще большую экономию памяти.

Идя дальше, вы все равно можете пройти до 24 верт на куб, но также использовать инстансинг. Каждый куб будет иметь фиксированный размер в вашем буфере вершин (1x1x1), и у вас будет коэффициент масштабирования и позиция (при условии, что ваши кубы не вращаются, если они имеют матрицу) в качестве данных для каждого экземпляра. В невращающемся случае вы получаете единовременную стоимость в 24 верта, но тогда каждому кубу нужно всего 6 поплавков, чтобы полностью указать. Во вращающемся случае вы рассматриваете 16 операций с плавающей запятой, но даже это является существенной экономией (в этом случае вы с большей вероятностью столкнетесь с узким местом на стороне процессора при матричных преобразованиях - для невращающегося случая построение матрицы на лету в ваш вершинный шейдер - даже если он сделан для каждой вершины, настолько глуп, что вам даже не нужно об этом беспокоиться).

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

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

У меня есть тестовый код в моем движке, который просто рисует кучу кубов, используя этот метод, и я могу легко прожевать более 300 000 кубов, по-прежнему очищая 60 кадров в секунду, на относительно низкоуровневом графическом процессоре и ничего не делая для оптимизации процесса , По общему признанию, я не освещаю и не текстурирую их, но у меня действительно включено альфа-смешивание, отключена выборка задней поверхности, и в целом он уравновешивается с моей частью «не делать ничего для оптимизации», поэтому он должен дать вам разумное представление о виде Бейсбольный стадион вы можете поразить этим методом

Максимус Минимус
источник
1
Я использовал инстансинг раньше, и он отлично работает для кубов до 40К. Но у меня есть как минимум 256 тыс. Кубов, и инстансинг тоже не справился. Использование SV_VertexID с поиском звучит очень многообещающе.
Теланор
Насколько велик был ваш буфер на экземпляр? Попытка поместить их все в огромный буфер может в конечном итоге задушить ваш GPU; Обычно я держу буферы для каждого экземпляра на достаточном пространстве для объектов размером 64 КБ (при необходимости разделяя вызовы отрисовки), использую шаблон сброса / отсутствия перезаписи и пишу напрямую в сопоставленный указатель вместо копирования из промежуточного массива, который работает очень хорошо ,
Максимус Минимус
Кроме того, важно сохранять небольшое количество карт. Отобразить / записать один куб / удалить 40 тысяч раз будет намного медленнее, чем отобразить / записать 40 тысяч кубов / удалить только один раз. Если вы делали первое, попробуйте переключиться на второе.
Maximus Minimus
15

Я думаю, что основная оптимизация, которую вы можете сделать, основана на том факте, что не каждому кубу понадобятся все 24 вершины . Фактически, единственные кубы, которым нужно 24 вершины, - это те, которые плавают в воздухе, что, вероятно, является редким явлением.

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

Изображение ниже демонстрирует эту концепцию, но в 2D для облегчения понимания. На изображении 11 занятых блоков (представленных закрашенными серыми кружками), для которых обычно требуется 4 x 11 = 44 ребра (4, потому что это квадрат, а не куб). Но, как вы можете видеть, вам действительно нужно рисовать края только тогда, когда они соприкасаются с пустым квадратом, который в данном случае составляет всего 8 ребер.

введите описание изображения здесь

Если такому простому примеру в 2D удалось уменьшить 44 ребра до 8 ребер, представьте себе выгоды в большом трехмерном мире ...

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

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

Дэвид Гувея
источник
1
Очень интересная статья. Я уже занимаюсь оптимизацией краев, что, безусловно, очень помогает. Я попробую геометрические шейдеры и посмотрю, сработает ли это.
Теланор
Вы имеете в виду, использовать геометрический шейдер и перекрестное произведение для вычисления нормалей? Я думал об этом, например, создать отдельную программу для плоских поверхностей (меня не интересуют текстуры).
дрета
@dreta Не только это, но и переход к точке, где вы отправляете только центроиды куба в виде списка точек, и все вершины излучаются GS. Возможно, закодируйте некоторую соседнюю информацию в точки, чтобы шейдер генерировал только те лица, которые действительно необходимы, хотя я и не думал, как это сделать.
Дэвид Гувея
Если вам нужна производительность, не используйте геометрический шейдер ... Почти всегда. Они полностью портят трубопровод. Если вы хотите сгенерировать геометрию на GPU, используйте вычислительный шейдер или openCL
Роберт Фрейзер