137 lines
6.1 KiB
Markdown
137 lines
6.1 KiB
Markdown
|
||
### **Сортировка полигонов на 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 <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-координате.
|
||
|
||
#### **Псевдокод**
|
||
```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/). |