aboutsummaryrefslogtreecommitdiff
path: root/docs/reference/msh.md
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-10-18 06:33:56 +0300
committerValentin Popov <valentin@popov.link>2026-10-18 06:33:56 +0300
commit0c6e7589f9793b4e399a86d3df680fe98a48c4cf (patch)
tree6a457288f2af5012d9145014a16e43aef13e5872 /docs/reference/msh.md
parentc77c078efee9ece70c3f82793ed002f82a95eb85 (diff)
downloadfparkan-0c6e7589f9793b4e399a86d3df680fe98a48c4cf.tar.xz
fparkan-0c6e7589f9793b4e399a86d3df680fe98a48c4cf.zip
fix: align native MSH face culling
Diffstat (limited to 'docs/reference/msh.md')
-rw-r--r--docs/reference/msh.md47
1 files changed, 47 insertions, 0 deletions
diff --git a/docs/reference/msh.md b/docs/reference/msh.md
index 165b750..a28514d 100644
--- a/docs/reference/msh.md
+++ b/docs/reference/msh.md
@@ -153,3 +153,50 @@ Byte `material_index` выбирает строку WEAR; high word at `+0x02` Ñ
`index_start + index_count` остаётся внутри type 6, а каждый использованный
индекс через `base_vertex` попадает в position stream. `vertex_count` и
`local_batch_index` доступны renderer для исходного draw contract.
+
+## Сторона грани в цветовом проходе
+
+В цветном проходе `Terrain.dll`, функция `0x100296F0`, сравнивает камеру с
+каждой гранью по знаку тройного произведения:
+
+```c
+d = dot(eye - v0, cross(v1 - v0, v2 - v0));
+```
+
+Проход оставляет грань только при `d > 0`. Raw `Batch20.flags` задаёт два
+исключения: `0x0002` пропускает программную проверку стороны, поэтому обратная
+грань не отбрасывается этим условием. С `0x4000` проверяется только первая
+грань записи: если `d <= 0`, цикл её граней прекращается; если `d > 0`,
+оставшиеся грани этой записи уже не проходят повторную программную проверку.
+`Terrain.dll!0x100296F0` также настраивает пакет этого цветного пути: flags по
+адресу `packet+0x128` равны `0x404` или `0x414`. Путь отправки в
+`Terrain.dll!0x1001D660` перед вызовом renderer vtable `+0x48` очищает только
+маску `0x1`; `Ngi32.dll!0x10007470` проверяет маску `0x4` этого аргумента. При
+установленной маске render state 22 получает `D3DCULL_NONE`, иначе —
+`D3DCULL_CW`. Оба значения CShade сохраняют маску `0x4`, поэтому в этом
+цветном пути аппаратное отсечение выключено, а набор обычных граней определяет
+программный тест `d > 0`. Raw-флаги `0x0002` и `0x4000` меняют этот тест, как
+описано выше.
+
+Статический Vulkan preview сохраняет каждую исходную запись `Batch20` одним
+диапазоном рисования:
+`append_static_preview_component_with_lightmaps` добавляет исходные индексы без
+перестановки, а в диапазон переносит `index_count` и исходный `first_index` с
+общим смещением компонента. Поэтому `0x4000` выбирает ту же первую грань, даже
+если диапазон получил другой материал для lightmap.
+
+Поскольку вершины preview переведены в мировые координаты, знак `d` для MSH
+диапазона корректируется знаком детерминанта полной матрицы размещения. Повороты
+узлов и mounts — единичные кватернионы с determinant `+1`; отрицательный object
+scale меняет знак. Renderer Vulkan задаёт `front_face=CLOCKWISE` и viewport с
+положительной высотой. Для используемых матриц legacy и free-flight preview
+при положительном determinant native-visible `d > 0` относится к Vulkan
+back-face; поэтому preview отсекает `FrontFace`. При отрицательном determinant
+режим меняется на `BackFace`.
+Для `0x0002` и `0x4000` аппаратное отсечение выключено, чтобы сохранить их
+программную политику. Отклонённый `0x4000` диапазон получает число индексов 0;
+каждый кадр это число заново вычисляется из исходного значения, поэтому после
+изменения положения камеры или opacity материала диапазон может вернуться в
+draw queue. Проверка первой грани
+применяется только к MSH-диапазонам цветовой мировой очереди; terrain и
+shadow/sun запросы её не используют.