6.1 KiB
6.1 KiB
Сортировка полигонов на PlayStation 1 (PS1)
PS1 не имеет аппаратной поддержки Z-буфера (depth buffer), поэтому правильный порядок отрисовки полигонов (сортировка) критически важен для корректного отображения 3D-сцен. Вот как это реализовано:
1. Основные методы сортировки
1.1. Ordering Table (OT)
Ordering Table — это главный механизм сортировки на PS1.
Работает по принципу связного списка в VRAM, где полигоны группируются по расстоянию.
Как это работает?
-
Инициализация OT:
- Создаётся массив указателей (например, на 256 или 1024 элемента).
- Каждый элемент соответствует диапазону глубин (Z-значений).
-
Добавление примитивов:
- Для каждого полигона вычисляется Z-координата (например, средняя точка).
- По Z-значению выбирается ячейка OT (чем дальше объект, тем меньше индекс).
- Полигон добавляется в список для этой ячейки.
-
Рендеринг:
- OT обрабатывается от дальних к ближним ячейкам (от 0 до N).
- Все примитивы в одной ячейке рисуются в порядке добавления.
Пример кода (PsyQ SDK)
#include <libgpu.h>
#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
Для сложных объектов (например, моделей) используется сортировка по ограничивающему объёму:
- Вычисляется сфера или AABB (коробка), охватывающая объект.
- Сортируются центры сфер по Z-координате.
Псевдокод
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). - Принудительный порядок для мелких объектов.
- Случайное смещение Z (
3. Пример для игры
Допустим, у нас есть:
- 10 коробок на разных расстояниях.
- 1 полупрозрачный полигон (вода).
Код рендеринга
// 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.