У меня есть мир на основе кубов, такой как Minecraft, и мне интересно, есть ли способ построить куб с менее чем 24 вершинами, чтобы я мог уменьшить использование памяти.
Это кажется мне невозможным по двум причинам: нормали не получатся правильными, а текстуры для лица не будут работать.
Это так или я не прав? Может быть, есть какая-нибудь необычная технология DX11, которая может помочь?
Изменить: просто чтобы уточнить, у меня есть 2 требования: мне нужно нормали поверхности для каждой грани куба, чтобы сделать правильное освещение, и мне нужен способ для адресации другого индекса в массиве текстуры для каждой грани куба
Ответы:
Если вам нужны только индивидуальные нормали, и если ваши текстовые координаты для лица строго 0/0, 0/1, 1/0, 1/1 (или похожи в соответствии с вашим макетом), то вы можете построить куб с 8 вершинами и 30 (полоса с перезапуском) или 36 (список) индексов. Извлеките нормали и текстовые координаты, используя поиск в массиве на основе SV_VertexID в вашем вершинном шейдере.
Это означает, что вам даже не нужно включать texcoords или нормали в ваш буфер вершин, что даст вам еще большую экономию памяти.
Идя дальше, вы все равно можете пройти до 24 верт на куб, но также использовать инстансинг. Каждый куб будет иметь фиксированный размер в вашем буфере вершин (1x1x1), и у вас будет коэффициент масштабирования и позиция (при условии, что ваши кубы не вращаются, если они имеют матрицу) в качестве данных для каждого экземпляра. В невращающемся случае вы получаете единовременную стоимость в 24 верта, но тогда каждому кубу нужно всего 6 поплавков, чтобы полностью указать. Во вращающемся случае вы рассматриваете 16 операций с плавающей запятой, но даже это является существенной экономией (в этом случае вы с большей вероятностью столкнетесь с узким местом на стороне процессора при матричных преобразованиях - для невращающегося случая построение матрицы на лету в ваш вершинный шейдер - даже если он сделан для каждой вершины, настолько глуп, что вам даже не нужно об этом беспокоиться).
Для текстур на лице, просто используйте массив текстур. Конечно, вы должны убедиться, что каждая такая текстура в массиве имеет одинаковый размер, и вам все равно нужно будет разбить текущий пакет, если сам массив нужно изменить, но в противном случае он отлично справится со своей задачей. Добавьте третью текстовую строку в определение вершины, которая определяет срез массива, который будет использоваться для каждой грани.
Вам не нужен GS с этим, и он должен работать быстрее, чем с ним, поскольку включение этапа геометрического шейдера налагает дополнительные издержки.
У меня есть тестовый код в моем движке, который просто рисует кучу кубов, используя этот метод, и я могу легко прожевать более 300 000 кубов, по-прежнему очищая 60 кадров в секунду, на относительно низкоуровневом графическом процессоре и ничего не делая для оптимизации процесса , По общему признанию, я не освещаю и не текстурирую их, но у меня действительно включено альфа-смешивание, отключена выборка задней поверхности, и в целом он уравновешивается с моей частью «не делать ничего для оптимизации», поэтому он должен дать вам разумное представление о виде Бейсбольный стадион вы можете поразить этим методом
источник
Я думаю, что основная оптимизация, которую вы можете сделать, основана на том факте, что не каждому кубу понадобятся все 24 вершины . Фактически, единственные кубы, которым нужно 24 вершины, - это те, которые плавают в воздухе, что, вероятно, является редким явлением.
Как правило, генерируют только четырехугольники для лиц, которые находятся в контакте с воздухом . Это означает, что если два куба соприкасаются друг с другом, вам не нужно создавать вершины для грани, к которой они соприкасаются.
Изображение ниже демонстрирует эту концепцию, но в 2D для облегчения понимания. На изображении 11 занятых блоков (представленных закрашенными серыми кружками), для которых обычно требуется 4 x 11 = 44 ребра (4, потому что это квадрат, а не куб). Но, как вы можете видеть, вам действительно нужно рисовать края только тогда, когда они соприкасаются с пустым квадратом, который в данном случае составляет всего 8 ребер.
Если такому простому примеру в 2D удалось уменьшить 44 ребра до 8 ребер, представьте себе выгоды в большом трехмерном мире ...
Это подход, описанный в этой статье , который я рекомендую вам прочитать, несмотря на то, что он нацелен на OpenGL. Понятия должны быть довольно универсальными все же.
Вы также можете, вероятно, использовать геометрический шейдер для генерации вершин на лету на графическом процессоре, что устраняет необходимость хранить их в памяти, но у меня нет опыта в этом, и я не знаю, насколько хорошо он будет работать для больших Мир.
источник