vault backup: 2025-04-18 23:10:56
This commit is contained in:
34
.obsidian/workspace.json
vendored
34
.obsidian/workspace.json
vendored
@@ -41,12 +41,12 @@
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "PERSONAL PROJECTS/PSX code - modules load and exec.md",
|
||||
"file": "PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "PSX code - modules load and exec"
|
||||
"title": "PS1 Geometry Transformation Engine"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -207,17 +207,21 @@
|
||||
},
|
||||
"active": "dd912cc876184c4f",
|
||||
"lastOpenFiles": [
|
||||
"PERSONAL PROJECTS/PSX code texture load unpack show and fade.md",
|
||||
"PERSONAL PROJECTS/PSX code - modules load and exec.md",
|
||||
"PERSONAL PROJECTS/PS1 Gamepad.md",
|
||||
"PERSONAL PROJECTS/PSX code - Load texture from SECTOR!.md",
|
||||
"PERSONAL PROJECTS/PSX code - Texture show from file.md",
|
||||
"PERSONAL PROJECTS/PS1 Vblank.md",
|
||||
"PERSONAL PROJECTS/PS1 MDEC.md",
|
||||
"PERSONAL PROJECTS/PS1 DMA.md",
|
||||
"PERSONAL PROJECTS/PS1 Gpu-DMA.md",
|
||||
"PERSONAL PROJECTS/PS1 DMA CD-ROM.md",
|
||||
"PERSONAL PROJECTS/LZSS C++ Lib.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/LZSS C++ Lib.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PSX code texture load unpack show and fade.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PSX code - Texture show from file.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PSX code - modules load and exec.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PSX code - Load texture from SECTOR!.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Vblank.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 MDEC.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gpu-DMA.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA CD-ROM.md",
|
||||
"WORK & PROJECTS/Mol/Ideas/Все идеи для Моли.md",
|
||||
"WORK & PROJECTS/Mol/Серверы/mail.mol-soft.ru.md",
|
||||
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/СМК/КУ_Чек_лист_10_ошибок_УД_скачивание.pdf",
|
||||
@@ -239,18 +243,14 @@
|
||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud",
|
||||
"WORK & PROJECTS/Mol/Серверы/git.moldev.ru.md",
|
||||
"WORK & PROJECTS/Ulab/передача сформированных заявки и протокола как ссылку или файл.md",
|
||||
"WORK & PROJECTS/Ulab/Доступы к точкам.md",
|
||||
"Структура объектов испытаний.png",
|
||||
"Схема связей юрлиц и адресов.png",
|
||||
"Структура объектов испытаний.png.0.pdnSave",
|
||||
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/АФ-01 Альбом форм.pdf",
|
||||
"WORK & PROJECTS/Mol/Серверы/Схема инфраструктуры.canvas",
|
||||
"WORK & PROJECTS/Ulab/Московский проект/ACCESS TABLE.md",
|
||||
"WORK & PROJECTS/Ulab/Автобан/щебень 5-20.xlsx",
|
||||
"WORK & PROJECTS/Ulab/Автобан/щебень 20-40.xlsx",
|
||||
"WORK & PROJECTS/Ulab/Автобан/песок природный.xls",
|
||||
"WORK & PROJECTS/Ulab/Автобан/грунт песчаный.xlsx",
|
||||
"WORK & PROJECTS/Mol/Серверы/Alfa cloud prod_canvas2doc-data/newdoc-node_f3d0e9a6d4d8e6a7_fromCanvas.md",
|
||||
"WORK & PROJECTS/Mol/Серверы/Alfa cloud prod.canvas",
|
||||
"PERSONAL PROJECTS/P2EP/cdRead.canvas",
|
||||
"P2EP/cdRead.canvas",
|
||||
|
||||
144
PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md
Normal file
144
PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md
Normal file
@@ -0,0 +1,144 @@
|
||||
### **Математический процессор (GTE) в PlayStation 1**
|
||||
|
||||
**Geometry Transformation Engine (GTE)** — это сопроцессор в PS1, отвечающий за ускорение математических операций, критичных для 3D-графики. Он работает параллельно с основным CPU (R3000A) и оптимизирован для:
|
||||
|
||||
1. **Перемножения матриц**
|
||||
2. **Вращения и трансформации вершин**
|
||||
3. **Расчёта перспективы и освещения**
|
||||
|
||||
---
|
||||
|
||||
## **1. Основные функции GTE**
|
||||
### **1.1. Быстрые матричные операции**
|
||||
GTE умеет:
|
||||
- Умножать **матрицу 3×3** на вектор (для поворота объектов).
|
||||
- Вычислять **матрицу модели-вида** (Model-View).
|
||||
- Обновлять **нормали объектов** для освещения.
|
||||
|
||||
**Пример**: Поворот вершины:
|
||||
```mips
|
||||
# Вход: матрица вращения в $a0, вершина (x,y,z) в $a1
|
||||
lw $t0, 0($a0) # Загружаем элемент матрицы
|
||||
lw $t1, 0($a1) # Загружаем X вершины
|
||||
mult $t0, $t1 # Умножаем (GTE делает это за 1 такт)
|
||||
mflo $t2 # Результат
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **1.2. Перспективное преобразование**
|
||||
GTE вычисляет **экранные координаты (X,Y)** из 3D-пространства:
|
||||
1. Учитывает **камеру** (матрица вида).
|
||||
2. Применяет **перспективу** (деление на Z).
|
||||
3. Оптимизирует расчёт **FOV** (поля зрения).
|
||||
|
||||
**Формула**:
|
||||
\[
|
||||
X_{screen} = \frac{X_{3D} \cdot scale}{Z_{3D}} + center\_x
|
||||
\]
|
||||
|
||||
---
|
||||
|
||||
### **1.3. Освещение и цвет**
|
||||
- GTE рассчитывает **интенсивность света** для вершин.
|
||||
- Поддерживает **до 3 источников света** (накладывает цвета).
|
||||
- Работает с **нормалями** (через скалярное произведение).
|
||||
|
||||
**Пример**:
|
||||
```mips
|
||||
# Нормаль в $a0, свет в $a1
|
||||
dp $t0, $a0, $a1 # Скалярное произведение (GTE)
|
||||
sll $t0, 8 # Яркость = 0..255
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **2. Зачем нужно перемножение матриц?**
|
||||
Матрицы используются для:
|
||||
1. **Поворота объектов**
|
||||
```math
|
||||
\begin{bmatrix}
|
||||
\cosθ & -\sinθ & 0 \\
|
||||
\sinθ & \cosθ & 0 \\
|
||||
0 & 0 & 1 \\
|
||||
\end{bmatrix} \cdot
|
||||
\begin{bmatrix} X \\ Y \\ Z \end{bmatrix}
|
||||
```
|
||||
2. **Масштабирования**
|
||||
```math
|
||||
\begin{bmatrix}
|
||||
S_x & 0 & 0 \\
|
||||
0 & S_y & 0 \\
|
||||
0 & 0 & S_z \\
|
||||
\end{bmatrix}
|
||||
```
|
||||
3. **Смещения (трансляции)**
|
||||
```math
|
||||
\begin{bmatrix} 1 & 0 & T_x \\ 0 & 1 & T_y \\ 0 & 0 & 1 \end{bmatrix}
|
||||
```
|
||||
|
||||
**GTE делает это за 1-2 такта** (вместо 10+ тактов на R3000A).
|
||||
|
||||
---
|
||||
|
||||
## **3. Пример: поворот куба на PS1**
|
||||
### **Код на C с ассемблерными вставками**
|
||||
```c
|
||||
#include <libgte.h>
|
||||
|
||||
typedef struct { short x, y, z; } Vertex;
|
||||
|
||||
void rotate_vertex(Vertex *v, int angle) {
|
||||
MATRIX rot_matrix;
|
||||
int sin, cos;
|
||||
|
||||
// Получаем синус/косинус угла (через GTE)
|
||||
gte_ldsin(angle, &sin);
|
||||
gte_ldcos(angle, &cos);
|
||||
|
||||
// Заполняем матрицу поворота вокруг Z
|
||||
rot_matrix.m[0][0] = cos; rot_matrix.m[0][1] = -sin;
|
||||
rot_matrix.m[1][0] = sin; rot_matrix.m[1][1] = cos;
|
||||
|
||||
// Умножаем матрицу на вершину (через GTE)
|
||||
gte_rtps(v->x, v->y, v->z, &rot_matrix, &v->x, &v->y, &v->z);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **4. Оптимизации через GTE**
|
||||
### **4.1. Пакетная обработка**
|
||||
- GTE может обрабатывать **до 3 вершин за инструкцию** (`rtpt`).
|
||||
- Пример для треугольника:
|
||||
```mips
|
||||
rtpt # Поворот 3 вершин сразу
|
||||
nop
|
||||
```
|
||||
|
||||
### **4.2. Отложенные вычисления**
|
||||
- Команды `nclip` и `avsz3` считают **площадь полигона** и **Z-буфер** без CPU.
|
||||
|
||||
### **4.3. Интеграция с GPU**
|
||||
- Результаты GTE (экранные X,Y,Z) передаются в **GPU** через DMA.
|
||||
- Это ускоряет рендеринг в 5-10 раз.
|
||||
|
||||
---
|
||||
|
||||
## **5. Сравнение с современными GPU**
|
||||
| Функция | PS1 (GTE) | Современный GPU |
|
||||
|-----------------------|----------------|----------------|
|
||||
| Матричные операции | 1-2 такта | 1 такт |
|
||||
| Макс. источников света| 3 | 100+ |
|
||||
| Поддержка шейдеров | Нет | Да |
|
||||
|
||||
---
|
||||
|
||||
## **6. Итог**
|
||||
- **GTE** — это «сердце» 3D-графики PS1, отвечающее за:
|
||||
- Поворот, масштабирование, перспективу.
|
||||
- Освещение и цвет.
|
||||
- **Без GTE** игры вроде *Tekken 3* или *Metal Gear Solid* работали бы на **1-2 FPS**.
|
||||
- Оптимизация под GTE — ключ к плавному рендерингу на PS1.
|
||||
|
||||
Для глубокого изучения смотрите [GTE Technical Reference](http://problemkaputt.de/psx-spx.htm#gtegeometrytransformationengine).
|
||||
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/).
|
||||
123
PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md
Normal file
123
PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md
Normal file
@@ -0,0 +1,123 @@
|
||||
Вот готовая программа для **PlayStation 1**, которая использует **MIPS-ассемблерные вставки** для сложения двух чисел через указатели. Результат возвращается в переменную основной программы.
|
||||
|
||||
---
|
||||
|
||||
### **1. Полный код (MAIN.C)**
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <libetc.h>
|
||||
|
||||
// Объявляем ассемблерную функцию
|
||||
int add_numbers_asm(int *a, int *b, int *result);
|
||||
|
||||
int main() {
|
||||
int num1 = 5;
|
||||
int num2 = 7;
|
||||
int result = 0;
|
||||
|
||||
// Вызываем ассемблерную функцию с указателями
|
||||
add_numbers_asm(&num1, &num2, &result);
|
||||
|
||||
// Выводим результат
|
||||
FntPrint("Result: %d + %d = %d\n", num1, num2, result);
|
||||
FntFlush(-1);
|
||||
|
||||
while (1) {
|
||||
VSync(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Реализация на MIPS-ассемблере
|
||||
int add_numbers_asm(int *a, int *b, int *result) {
|
||||
int ret;
|
||||
asm volatile (
|
||||
"lw $t0, 0(%1) \n" // Загружаем *a в $t0
|
||||
"lw $t1, 0(%2) \n" // Загружаем *b в $t1
|
||||
"add $t2, $t0, $t1 \n" // Складываем: $t2 = $t0 + $t1
|
||||
"sw $t2, 0(%3) \n" // Сохраняем результат по адресу *result
|
||||
"move %0, $t2 \n" // Возвращаем результат через регистр
|
||||
: "=r" (ret) // Выходные операнды
|
||||
: "r" (a), "r" (b), "r" (result) // Входные операнды
|
||||
: "$t0", "$t1", "$t2" // Разрушаемые регистры
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **2. Как это работает?**
|
||||
1. **Передача указателей в ассемблер**
|
||||
Функция `add_numbers_asm` принимает три указателя:
|
||||
- `a` — адрес первого числа,
|
||||
- `b` — адрес второго числа,
|
||||
- `result` — адрес для сохранения результата.
|
||||
|
||||
2. **Ассемблерная вставка** (`asm volatile`):
|
||||
- `lw` — загружает значения из памяти по указателям.
|
||||
- `add` — складывает числа.
|
||||
- `sw` — сохраняет результат по адресу `result`.
|
||||
- `move` — возвращает значение через регистр.
|
||||
|
||||
3. **Доступ к результату**
|
||||
Результат будет:
|
||||
- В переменной `result` (через указатель).
|
||||
- В возвращаемом значении функции (если нужно).
|
||||
|
||||
---
|
||||
|
||||
### **3. Компиляция и запуск**
|
||||
1. Скомпилируйте через **PsyQ SDK**:
|
||||
```bash
|
||||
ccpsx MAIN.C -o ADD_DEMO.EXE
|
||||
```
|
||||
|
||||
2. Запишите на диск и запустите на эмуляторе или консоли.
|
||||
На экране появится:
|
||||
```
|
||||
Result: 5 + 7 = 12
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **4. Важные нюансы**
|
||||
- **Регистры MIPS**:
|
||||
- `$t0`–`$t9` — временные регистры (можно использовать без сохранения).
|
||||
- `$s0`–`$s7` — должны сохраняться (если используются).
|
||||
|
||||
- **Разрушаемые регистры**:
|
||||
Указаны в конце `asm volatile` (чтобы компилятор не использовал их для оптимизации).
|
||||
|
||||
- **Опасность**:
|
||||
Если передать **неверные указатели**, PS1 уйдёт в **краш** (нет защиты памяти).
|
||||
|
||||
---
|
||||
|
||||
### **5. Пример с глобальными переменными**
|
||||
Если нужно работать с глобальными переменными напрямую:
|
||||
```c
|
||||
int global_num1 = 10;
|
||||
int global_num2 = 20;
|
||||
|
||||
void add_globals_asm() {
|
||||
asm volatile (
|
||||
"la $t0, global_num1 \n" // Загружаем адрес global_num1
|
||||
"lw $t1, 0($t0) \n" // Читаем значение
|
||||
"la $t0, global_num2 \n"
|
||||
"lw $t2, 0($t0) \n"
|
||||
"add $t1, $t1, $t2 \n"
|
||||
"sw $t1, 0($t0) \n" // Сохраняем сумму в global_num2
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **6. Итог**
|
||||
- **Ассемблерные вставки** дают полный контроль над железом PS1.
|
||||
- **Указатели** передаются через регистры (`$a0`–`$a3` в MIPS).
|
||||
- **Результат** можно получить через память или возвращаемое значение.
|
||||
|
||||
Этот подход используется в оптимизированных частях игр (например, в рендеринге или физике).
|
||||
Reference in New Issue
Block a user