Files
SergObsidian/PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md
2025-04-18 23:10:56 +05:00

6.1 KiB
Raw Blame History

Сортировка полигонов на 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)

#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

Для сложных объектов (например, моделей) используется сортировка по ограничивающему объёму:

  1. Вычисляется сфера или AABB (коробка), охватывающая объект.
  2. Сортируются центры сфер по 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).
    • Принудительный порядок для мелких объектов.

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.