### **Сортировка полигонов на PlayStation 1 (PS1)** PS1 не имеет аппаратной поддержки **Z-буфера** (depth buffer), поэтому правильный порядок отрисовки полигонов (сортировка) критически важен для корректного отображения 3D-сцен. Вот как это реализовано: --- ## **1. Основные методы сортировки** ### **1.1. Ordering Table (OT)** **Ordering Table** — это главный механизм сортировки на PS1. Работает по принципу **связного списка** в VRAM, где полигоны группируются по расстоянию. #### **Как это работает?** 1. **Инициализация OT**: - Создаётся массив указателей (например, на 256 или 1024 элемента). - Каждый элемент соответствует диапазону глубин (Z-значений). 2. **Добавление примитивов**: - Для каждого полигона вычисляется **Z-координата** (например, средняя точка). - По Z-значению выбирается **ячейка OT** (чем дальше объект, тем меньше индекс). - Полигон добавляется в список для этой ячейки. 3. **Рендеринг**: - OT обрабатывается **от дальних к ближним** ячейкам (от 0 до N). - Все примитивы в одной ячейке рисуются в порядке добавления. #### **Пример кода (PsyQ SDK)** ```c #include #define OT_LEN 256 // Размер Ordering Table uint32_t ot[OT_LEN]; // Сама таблица void init_ot() { ClearOTagR(ot, OT_LEN); // Очистка OT } void add_polygon(POLY_F4 *poly, int z) { // Вычисляем индекс в OT (0 = дальний, OT_LEN-1 = ближний) int ot_entry = (z >> 8) & (OT_LEN - 1); // Простейшее масштабирование Z // Добавляем полигон в OT addPrim(ot + ot_entry, poly); } void render_frame() { DrawOTag(ot + (OT_LEN - 1)); // Рендеринг OT (от ближних к дальним) } ``` --- ### **1.2. Сортировка по Bounding Box** Для сложных объектов (например, моделей) используется **сортировка по ограничивающему объёму**: 1. Вычисляется **сфера или AABB** (коробка), охватывающая объект. 2. Сортируются **центры сфер** по Z-координате. #### **Псевдокод** ```c struct Object { int center_z; POLY_F4 *polys; }; void sort_objects(Object *objs, int count) { qsort(objs, count, sizeof(Object), compare_by_z); } int compare_by_z(const void *a, const void *b) { return ((Object*)a)->center_z - ((Object*)b)->center_z; } ``` --- ### **1.3. Priority Groups** Некоторые игры (например, *Crash Bandicoot*) используют **приоритетные группы**: - Полигоны делятся на **статические** (уровень) и **динамические** (персонажи). - Статические рисуются через OT, динамические — поверх них. --- ## **2. Оптимизации** ### **2.1. Z-Сортировка только для прозрачных объектов** - Непрозрачные полигоны рисуются **без сортировки** (через алгоритм художника). - Прозрачные (с полупрозрачностью) сортируются **строго от дальних к ближним**. ### **2.2. Двойная OT** - **Одна OT для непрозрачных**, вторая — **для прозрачных** полигонов. - Позволяет уменьшить накладные расходы. ### **2.3. Субпиксельная корректировка** - Для борьбы с **Z-файтингом** (мерцание полигонов) используется: - Случайное смещение Z (`z += rand() % 4`). - Принудительный порядок для мелких объектов. --- ## **3. Пример для игры** Допустим, у нас есть: - **10 коробок** на разных расстояниях. - **1 полупрозрачный полигон** (вода). #### **Код рендеринга** ```c // 1. Инициализация init_ot(); // 2. Добавление непрозрачных полигонов (коробки) for (int i = 0; i < 10; i++) { add_polygon(&boxes[i], boxes[i].z); } // 3. Добавление прозрачного полигона (вода) add_polygon(&water_poly, water_z); // 4. Рендеринг render_frame(); ``` --- ## **4. Проблемы и решения** | Проблема | Решение | |------------------------|----------------------------------| | **Мерцание полигонов** | Субпиксельная корректировка Z. | | **Низкая производительность** | Уменьшение размера OT. | | **Неправильный порядок** | Ручная настройка приоритетов. | --- ## **5. Итог** - **Ordering Table** — основа сортировки на PS1. - **Для сложных сцен** комбинируют OT, Bounding Box и приоритетные группы. - **Оптимизации** нужны для борьбы с артефактами. Этот подход использовался в играх типа *Tekken 3* и *Resident Evil*. Для глубокого понимания изучите [документацию PsyQ](http://psx.arthus.net/sdk/PsyQ/DOCS/).