Т. к. формат очень старый и в своём первоначальном виде плохо подходит для Direct3D 11, было решено написать конвертер, который брал бы исходные данные и перерабатывал их таким образом, чтобы можно было легко загружать их и оперировать ими на GPU. Для простоты формат я назвал U(nified)MD2.
Во-первых, вершины всех фреймов в формате ubyte собраны вместе и заливаются в один буфер вершин. Для расчёта промежуточного кадра буфер вершин подключается к input slot 0 и 1, для первого слота указывается смещение для текущего кадра, а для второго - смещение для следующего за текущим кадра. Позиция вершины рассчитывается в вершинном шейдере простой интерполяцией двух атрибутов.
Для геометрии модели считается adjacency и записывается вместо стандартных индексов треугольников. Такой единый индексный буфер можно использовать как для поиска силуэтов, так и для стандартного рисования модели (железо игнорирует смежные индексы, если геометрический шейдер не установлен или не нуждается в них).
Данные об анимациях и их длинах также были переработаны для более удобного чтения (нет необходимости в парсинге).
Сложнее всего было решить, как поступить с текстурными координатами. Из-за швов (seams) в MD2 моделях существуют вершины, которые имеют одинаковую позицию, но разные текстурные координаты, и использовать один индексный буфер в таком случае невозможно. Графические ускорители никогда не поддерживали несколько индексных буферов (по очевидным причинам - сложность pre- и post-TnL кэшей увеличивается), поэтому простых решений два: индексировать на CPU или размножать вершины с разными текстурными координатами. Т. к. модели в Quake II геометрически очень просты, формировать буфер на CPU легко, но это не интересно. Размножение вершин возможно и обычно так и поступают в стандартных моделях, но в данном случае используется key frame анимация с множеством копий одних и тех же вершин, и дублирование станет многократным - решение получается некрасивым.
Наиболее правильный подход в данном случае - размножить uv координаты так, чтобы на каждый треугольник приходилось по три uv координаты (т. к. текстурные координаты общие для всех кадров, их увеличение несущественно). Теперь в геометрическом шейдере можно использовать семантику SV_PrimitiveID для индексации буфера текстурных координат, который подключается как shader resource:
Bufferg_buffer : register(t0);
uint pid: SV_PrimitiveID;
...
float2 tex = g_buffer.Load(pid * 3 + i);
где i - номер вершины треугольника.
Внедрение простого геометрического шейдера в современных GPU не приводит к существенному падению производительности, поэтому можно смело использовать такой подход. Впрочем, в случае с MD2 это скорее просто спортивный приём :)
И последнее: в MD2 текстурные координаты хранятся в формате ushort (значения делятся на высоту и ширину скина, получается float), но конвертер преобразует их в half.
ну а где сам конвертер?
ОтветитьУдалить