vault backup: 2025-04-18 23:10:56
This commit is contained in:
137
PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md
Normal file
137
PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md
Normal file
@@ -0,0 +1,137 @@
|
||||
|
||||
### **Сортировка полигонов на 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/).
|
||||
Reference in New Issue
Block a user