diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/reference/environment-effects.md | 99 | ||||
| -rw-r--r-- | docs/reference/materials.md | 7 | ||||
| -rw-r--r-- | docs/reference/msh.md | 47 | ||||
| -rw-r--r-- | docs/tomes/05-render.md | 38 |
4 files changed, 183 insertions, 8 deletions
diff --git a/docs/reference/environment-effects.md b/docs/reference/environment-effects.md index fdc29f0..0435a6a 100644 --- a/docs/reference/environment-effects.md +++ b/docs/reference/environment-effects.md @@ -104,6 +104,10 @@ N = round_even( координаты, и к каждой оси применяется floor-based wrap; 5. после wrap точка снова переводится в мир, а её хвост сбрасывается на голову. +Повторное обновление на том же времени имеет нулевой `dt`: позиция капли и +сохранённое начало хвоста остаются прежними. Хвост продвигается только при +положительном шаге; wrap по-прежнему сбрасывает его на голову. + Скорости не принадлежат системе координат камеры: ```text @@ -143,6 +147,24 @@ slot `+6c`): ширина `RECT` делится на горизонтальныÐ исходную таблицу знаков и минимальный depth fade `0.1`. Renderer сам решает, как загрузить этот квадрат и как смешать его материал. +## Точечный свет из opcode 1 + +Preview вычисляет generic Op1 отдельно от визуальных команд. Переданный +владельцем `command_time` сравнивается с началом и концом интервала из body +opcode 1; обе границы включены, а коэффициент выборки равен +`(command_time - start) / (end - start)`. Заголовочная длительность FXID не +заменяет этот интервал. Для нулевой ширины адаптер не создаёт кадр света, +поскольку у команды нет конечного коэффициента интерполяции. + +Позиция, направление, цвет и range интерполируются по концам команды. +Позиция и направление переводятся через основу родителя; направление после +этого нормализуется, а нулевой вектор остаётся нулевым. Range сохраняет +авторское значение без ограничения снизу. Типы Op1 `1`, `2`, `5`, `6` и `7` +выбирают point-light selector `1`; их native flags сохраняются. Типы `3` и +`4` выбирают другие классы записей LightManager и не попадают в generic список +точечного света. У `LightningEffect` выборка тех же полей использует отдельные +ограничение по длительности FXID и правила безопасной обработки. + ## Молния и звуковые события `decode_env_lightning_fxid` извлекает из FXID длительность, ссылки opcode 3 и @@ -236,6 +258,83 @@ Native `z = 0.999` не означает, что спрайт гарантиро native значение сохраняется для совместимости, но само по себе не обещает окклюзию солнца всей геометрией местности. +## Геометрия визуальных FX-команд + +`fparkan-fx::fx_visual` формирует кадры для двух подтверждённых вариантов +`f_gener_ball`. Op4 принимает mode 0 с положительным знаменателем в `body+0xC4` +и выдаёт camera-facing quad; расстояние камеры считается через native +component-wise projection родительской матрицы. Op9 принимает mode 2: +селектор `body+0xC4` со значением 0, 1 или 2 отображается в native flag base +3, 5 или 6 и выбирает одну из трёх сеток; категория render flags выбирает её +детализацию. `body+0xC8` выбирает UV path: +нулевое значение проецирует позицию вершины на XY, ненулевое использует +фиксированные координаты quad и cap. Кадр сохраняет MAT0 resource, фазу, +opacity, вершины и triangle indices для renderer. + +Evaluator получает готовые command body, phase, camera point и внешнюю +матрицу. Выбор Control row, manager gates, owner attachment, header jitter и +global RNG остаются задачей владельца. `fparkan-game` пока использует для Op9 +категорию 0 с наибольшей детализацией; выбор категории по projected size ещё +не реализован. + +Для Op3 поддерживаются body-типы 0, 1 и 2. Поля отсчитываются от +`FxCommand.raw_body`, то есть после 4-байтового command word. Типы 0 и 1 +используют общие position/scale/phase/opacity tracks и camera-facing основу; +тип 1 и тип 2 также интерполируют ось, а тип 2 строит basis через native +D110-порядок. Все три evaluator-а принимают уже собранную матрицу владельца и +не выбирают Control row или attachment. Текущий путь для типов 0 и 1 +предполагает native render context 0: `Effect.dll` проверяет общий gate +`context + 0x60 < 8`, а API этих evaluator-ов не выбирает другой context. +Evaluator типа 2 принимает индекс context явно и учитывает этот gate в `active`. + +## Частицы Op7 + +`fparkan-fx::op7` вычисляет фиксированный набор частиц Op7 по body команды, +фазе эффекта, матрице владельца, позиции камеры и render context. После +инициализации состояние команды сохраняет случайно изменённые треки позиции +и масштаба. Body задаёт время групп, opacity, фазу материала и вертикальное +ускорение; последнее масштабируется переданным world scalar и применяется к +копии матрицы владельца каждой активной группы. Текущий preview +`fparkan-game` передаёт `world_scalar = 10.0`; чтение действующей настройки +мира пока не подключено. + +Часы активной группы обновляются до применения detail cutoff отдельной +частицы. Cutoff сравнивает ordinal render context с постоянным порогом слота. +`Effect.dll` `0x1300` использует тот же порядок, поэтому скрытие слота не +останавливает часы его активной группы. Поток частиц последовательно задаёт +случайные изменения позиции и масштаба; для порогов видимости используется +отдельный поток. Шаг LFSR совпадает с нативным переходом двух половин, однако +семена отдельных экземпляров лишь детерминированно заменяют process-global +состояние и не воспроизводят общий порядок вызовов. + +## Частицы Op8 + +`fparkan-fx::smoke` разбирает body Op8, хранит кольцевой пул команды и выдаёт +quad-ы с ориентацией к камере для активных слотов. Нативная нормализованная +фаза окна ограничивается диапазоном 0–1 и задаёт интервал проверки следующего события; +сравнение строгое (`schedule_base + interval < update_clock`). Все события +catch-up в одном обновлении проверяются по тому же нормализованному интервалу; +после события нативный код продвигает базу расписания интервалом, вычисленным +по сырой фазе эффекта, а возраст слота считает по нормализованному интервалу. +Когда фаза равна единственной границе окна, деление `0/0` даёт NaN, который +нативный unordered-путь сравнения ограничивает нулём. + +Нулевая база расписания служит признаком начального состояния: обновление +сохраняет текущую опору эмиттера и базу времени, не создавая частицу. Если +первое время равно нулю, следующее обновление повторно захватывает опору. При +событии скорость опоры считается от сохранённой позиции до текущей за время +от базы расписания; слот смещает сохранённую опору на `скорость * due_interval`. +Обновление без событий не переносит сохранённую опору к текущему владельцу. +Откат часов корректирует только базу расписания до текущего времени: слоты, +опора и три потока случайных +чисел не сбрасываются. + +Evaluator принимает отдельные начальные состояния для эмиттера, знаковых +отклонений и материала. Переход каждого потока совпадает с общим native LFSR, +но эти локальные seed не воспроизводят порядок process-global вызовов игры. +Предел 100000 событий catch-up — защитная граница evaluator-а; соответствующего +лимита в исследованном native цикле не обнаружено. + ## Что остаётся за владельцем `EnvironmentSystem` не извлекает камеру из renderer, не разрешает материалы diff --git a/docs/reference/materials.md b/docs/reference/materials.md index c148bc8..435bd6e 100644 --- a/docs/reference/materials.md +++ b/docs/reference/materials.md @@ -132,6 +132,13 @@ ping-pong нечётный цикл идёт в обратном направлÐ sampler `animation_block_index` уже выбран вызывающим runtime из block table; packed WEAR handle и номер строки WEAR являются отдельными значениями. +Для native effect path с явной normalized phase режим блока не вычисляется: +конечное значение вне `0..=1` заменяется на `0.5`, затем phase умножается на +последний `end_time_ms` и усекается до целого tick. Поиск интервала идёт от +последнего ключа к первому. При phase `1.0` tick равен duration, поэтому ни один +интервал не подходит: выбирается key 0 и общий interpolation path может +экстраполировать за пределы его первого интервала. + ## Fallback Material resolve: 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 запросы её не используют. diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md index b04af31..c8bdf4e 100644 --- a/docs/tomes/05-render.md +++ b/docs/tomes/05-render.md @@ -625,15 +625,20 @@ Lightmap не является обычной diffuse texture. WEAR содерж отдельным slot или texture stage. Замена lightmap предварительным умножением в diffuse texture ломает LOD, atlas coordinates и динамическую модуляцию. -Vulkan preview строит projected shadows для выбранных зданий и роботов, -отбрасывает spheres вне шести clip-плоскостей с радиусом `sphere + 100` и +Vulkan preview строит проецируемые тени для объектов, отбрасывающих тени, +отбрасывает сферы вне шести clip-плоскостей с радиусом `sphere + 100` и сохраняет порядок видимых кандидатов; frame builder обрабатывает не более 20 -casters. Текущая реализация выделяет страницы в atlas `256 x 256` с 28 page -slots и использует одну smoothing pass. Вызов preview передаёт `fade = 1.0` и -LOD defaults: minimum LOD `1` и detail multiplier `1.0` отдельно для зданий и -роботов. Rust-путь не загружает `shade.cfg`: эти значения задаются кодом, а -параметры файла пока не влияют на preview. Проекция учитывает вклад -directional и point lights. +объектов. Текущая реализация выделяет страницы в atlas `256 x 256` с 28 page +slots и использует одно сглаживание. Preview применяет native defaults +`RobShadowsOn = true` и `BldShadowsOn = false`: объект kind `4` проверяет +первый флаг, остальные kinds — второй. Поэтому роботы BTLU остаются объектами, +отбрасывающими тени, а объекты FORT и STAT их не создают. Preview пока не +загружает `shade.cfg`, поэтому значения из пользовательского файла не меняют +список объектов, отбрасывающих тени. Проверка действует только на проецируемые +тени: отдельный список объектов для затенения солнца по-прежнему включает +FORT, BTLU и STAT. Вызов preview передаёт `fade = 1.0` и LOD defaults: +minimum LOD `1` и detail multiplier `1.0` отдельно для зданий и роботов. +Проекция учитывает вклад directional и point lights. Receiver projection обрезает projected quad по рёбрам треугольника. Native ray query descriptor в `+0x10` требует наличия всех переданных bits, а descriptor @@ -955,6 +960,23 @@ for (face, assignment) in mesh.faces.iter().zip(assignments.iter()) { } ``` +Подготовка BAS вынесена в `fparkan-terrain::build_basement_foundations`. +Функция получает внешние и внутренние кольца в порядке размещения, строит +упорядоченные пересечения внешней границы с текущей поверхностью и возвращает +исходные фрагменты рельефа вместе с треугольниками отмостки в одном наборе. +`TerrainWorld::with_basement_foundation` принимает этот набор во владение и +устанавливает те же координаты и маски в BVH высотных запросов и пересечений. +Предпросмотр миссии на Vulkan пока строит только LOD0: связывание BAS-записей +с этой подготовкой ещё не подключено, поэтому наличие API не означает, что +геометрия миссии уже обрезана. + +Внешнее кольцо должно лежать на области LOD0, а каждый его сегмент — оставаться +покрытым текущей поверхностью. Непокрытый сегмент или пересекающиеся контуры +дают ошибку; карта не остаётся частично обрезанной. Первичная нормализация +использует исходные грани и соседей LOD0, последующие пересечения и вырезания — +канонические фрагменты после предыдущих размещений. Соответствие динамических +соседей, создаваемых нативным движком, пока не моделируется. + ## Материалы ландшафта Рядом с `Land.msh` лежат `Land1.wea` и `Land2.wea`. Старший байт |
