docs: translate render frame reference
Docs Deploy / Build and Deploy MkDocs (push) Successful in 34s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 34s
This commit is contained in:
2 files changed
+147
-151
No files matched your search
+142
-147
@@ -1,174 +1,169 @@
|
||||
# Render frame
|
||||
# Кадр отрисовки
|
||||
|
||||
Кадр является последней стадией цикла, а не самостоятельной функцией renderer-а.
|
||||
До draw calls уже накоплен input, рассчитан tick, применены отложенные операции,
|
||||
выбрана камера и обновлён 3D sound listener.
|
||||
Кадр завершает цикл и не является отдельной операцией рендерера. До вызовов
|
||||
отрисовки собирается ввод, вычисляется такт, применяются отложенные операции,
|
||||
выбирается камера и обновляется слушатель 3D-звука.
|
||||
|
||||
## Frame skeleton
|
||||
## Порядок кадра
|
||||
|
||||
```text
|
||||
system messages and input
|
||||
-> simulation calculation
|
||||
-> deferred object operations
|
||||
-> animation and transforms
|
||||
-> camera and sound listener
|
||||
-> visibility and render queues
|
||||
-> materials and draw passes
|
||||
-> renderer completion
|
||||
-> end-of-render callbacks and UI
|
||||
системные сообщения и ввод
|
||||
-> расчёт симуляции
|
||||
-> отложенные операции над объектами
|
||||
-> анимация и преобразования
|
||||
-> камера и звуковой слушатель
|
||||
-> видимость и очереди отрисовки
|
||||
-> материалы и проходы отрисовки
|
||||
-> завершение рендерера
|
||||
-> обратные вызовы после отрисовки и UI
|
||||
```
|
||||
|
||||
В `World3D::stdRenderGame` доказан крупный порядок: camera передаётся Terrain,
|
||||
настраиваются viewport/matrices, вызываются renderer boundary slots,
|
||||
устанавливается `in_render`, выполняется traversal мира, закрывается world/shade
|
||||
pass, вызывается renderer completion, снимается `in_render`, рассылается
|
||||
end-of-render.
|
||||
По анализу вызовов установлен общий порядок в `World3D::stdRenderGame`: камера
|
||||
передаётся в Terrain, задаются `viewport` и матрицы, вызываются граничные слоты
|
||||
рендерера, выставляется `in_render`, обходится мир, завершаются проходы мира и
|
||||
затенения, вызывается завершение рендерера, снимается `in_render`, затем
|
||||
рассылается `end-of-render`.
|
||||
|
||||
## Draw item
|
||||
## Элемент отрисовки
|
||||
|
||||
Подготовленный draw item содержит:
|
||||
Подготовленный элемент отрисовки содержит:
|
||||
|
||||
- node world matrix;
|
||||
- batch flags and index range;
|
||||
- WEAR material handle;
|
||||
- MAT0 active phase and coefficients;
|
||||
- texture handle;
|
||||
- optional lightmap handle;
|
||||
- render phase and sorting key;
|
||||
- legacy pipeline state.
|
||||
- мировую матрицу узла;
|
||||
- флаги пакета `batch` и диапазон индексов;
|
||||
- дескриптор материала WEAR;
|
||||
- активную фазу и коэффициенты MAT0;
|
||||
- дескриптор текстуры;
|
||||
- необязательный дескриптор карты освещения;
|
||||
- фазу отрисовки и ключ сортировки;
|
||||
- состояние конвейера устаревшей отрисовки.
|
||||
|
||||
Подготовленный item должен ссылаться на immutable данные кадра. Изменение phase
|
||||
или texture cache посреди прохода не должно менять уже собранную очередь.
|
||||
Подготовленный элемент должен ссылаться на неизменяемые данные кадра. Изменение
|
||||
фазы или кэша текстур посреди прохода не должно менять уже собранную очередь.
|
||||
|
||||
## MAT0 state and transparent backgrounds
|
||||
## Состояние MAT0 и прозрачные фоны
|
||||
|
||||
For mission world ranges, the selected MAT0 material supplies its native
|
||||
pipeline category. The category sets blend and alpha-test state while preserving
|
||||
the range's depth and cull state; an animated material selector updates the
|
||||
category with the selector. Queue membership is independent: sampled opacity
|
||||
below one or native batch flags `0x108` mark a world range transparent, and a
|
||||
queued range with depth enabled tests depth without writing it. Fixed
|
||||
environment ranges keep their explicit states.
|
||||
Для диапазонов мира миссии выбранный материал MAT0 задаёт нативную категорию
|
||||
конвейера. Категория определяет смешивание и альфа-тест, сохраняя настройки
|
||||
проверки глубины и отсечения граней. Если селектор материала анимируется,
|
||||
вместе с ним обновляется и категория.
|
||||
Принадлежность к очереди определяется отдельно: прозрачным считается диапазон
|
||||
мира с выбранной прозрачностью меньше единицы или с нативными флагами пакета
|
||||
`batch` `0x108`. Такой диапазон при включённой проверке глубины не записывает
|
||||
глубину. За фиксированными диапазонами окружения сохраняются их явные состояния.
|
||||
|
||||
The fixed-camera preview explicitly marks nebula/stars, dome and cloud ranges as
|
||||
transparent backgrounds. Opaque world ranges stay in their world slots; the
|
||||
transparent world queue is sorted back-to-front and inserted immediately after
|
||||
the last marked background. Other fixed ranges retain their relative order.
|
||||
Thus cloud layers can be drawn before transparent foliage, while later sun,
|
||||
weather and other foreground ranges keep their existing relative order. This
|
||||
is a narrow queue rule, not a reordering of every sky or effects pass.
|
||||
В превью с фиксированной камерой диапазоны туманности и звёзд, купола и облаков
|
||||
явно помечаются как прозрачный фон. Непрозрачные диапазоны мира остаются на
|
||||
своих местах; прозрачная очередь мира сортируется от дальних элементов к
|
||||
ближним и вставляется сразу после последнего помеченного фона. Порядок остальных
|
||||
фиксированных диапазонов сохраняется. Поэтому облака могут отрисовываться перед
|
||||
прозрачной листвой, а расположенные позднее солнце, погода и другие передние
|
||||
эффекты сохраняют свой относительный порядок. Это локальное правило очереди, а
|
||||
не перестановка всех проходов неба или эффектов.
|
||||
|
||||
## Regression evidence
|
||||
## Проверки
|
||||
|
||||
`cargo test -p fparkan-render-vulkan --lib material_category_and_transparency_preserve_world_state_in_either_order --offline`
|
||||
checks that category 1 remains source-alpha with alpha testing, retains depth
|
||||
and cull settings in either update order, and rejects unsupported categories.
|
||||
`cargo test -p fparkan-render-vulkan --lib tree_canopy_queue_follows_sky_and_precedes_foreground_effects --offline`
|
||||
checks the explicit queue order: screen gradient, opaque terrain/building,
|
||||
shadow, nebula/dome/clouds, far-to-near transparent canopy, then sun/weather.
|
||||
`cargo test --locked --offline -p fparkan-render-vulkan --lib material_category_and_transparency_preserve_world_state_in_either_order`
|
||||
Проверяет, что категория 1 сохраняет смешивание `source-alpha` и альфа-тест,
|
||||
сохраняет настройки проверки глубины и отсечения граней при любом порядке
|
||||
обновления и отклоняет неподдерживаемые категории.
|
||||
`cargo test --locked --offline -p fparkan-render-vulkan --lib tree_canopy_queue_follows_sky_and_precedes_foreground_effects`
|
||||
Проверяет заданный порядок очереди: градиент экрана, непрозрачная местность и
|
||||
здание, тень, туманность, купол и облака, прозрачная крона от дальних элементов
|
||||
к ближним, затем солнце и погода.
|
||||
|
||||
Viewer-only paired readbacks used `--frames 3 --validation
|
||||
--legacy-camera-capture` with the pre-fix and patched builds. On AutoDemo TMA
|
||||
object 4 (`wor_l_n1.dat`, `fr_l_plant`), the 1280x720 camera at eye
|
||||
`[464.319, 904.719, 38.0]`, aimed at `[374.319, 814.719, 12.0]` with FOV
|
||||
`0.62`, changed the two black facade panels to tinted, textured portal
|
||||
surfaces. On Mission.01 object 12 (`s_tree_04`), the 1280x1024 camera at eye
|
||||
`[492.63855, 312.90244, 46.5]` aimed at
|
||||
`[492.63855, 442.90244, 55.0]` crosses the canopy against open sky; paired
|
||||
three-frame captures at the same synthetic atmosphere phase (600 seconds) show
|
||||
the patched build restoring the missing upper/right fronds along that sky
|
||||
boundary. Both runs reported clean Vulkan validation. These captures verify our
|
||||
preview behavior and do not prove the native renderer's pass order, portal
|
||||
transmittance or exact color.
|
||||
## Свидетельства диспетчеризации камеры GOG
|
||||
|
||||
## GOG camera dispatch evidence
|
||||
|
||||
For the GOG `World3D.dll` baseline with SHA-256
|
||||
Для версии GOG `World3D.dll` с SHA-256
|
||||
`17e4a3089b2583a8cf2356c9db0390b1aba138356a09130d79b4e7e4791da61e`,
|
||||
the exported `stdRenderGame` is RVA `0x13BD0`. It first calls
|
||||
`Terrain::stdSetCurrentCamera2(camera)`, stores the camera pointer only for
|
||||
the frame, and clears it before return. `sendEndOfRender` is a separate export
|
||||
at RVA `0x13D90`. This is frame-order evidence only: the camera ABI, matrices
|
||||
and viewport values are not recovered by this call-order analysis. The
|
||||
implemented preview path below accepts selector-0 input produced through the
|
||||
[native frame capture workflow](../../tools/native-frame-capture/README.md).
|
||||
The capture workflow also records an observed mission path and, when
|
||||
its thread/generation and clock checks succeed, an `atmosphere_seconds` sample.
|
||||
For a fixed-camera preview, the renderer uses that optional absolute schedule
|
||||
phase when no `--atmosphere-seconds` override is supplied and keeps schedule
|
||||
sampling at that exact phase across readback frames. An explicit CLI value takes
|
||||
precedence. The phase sample is not full simulation time: weather, RNG, and
|
||||
other mission state remain unknown, so this evidence does not establish
|
||||
full-frame parity.
|
||||
экспорт `stdRenderGame` находится по RVA `0x13BD0`. Вначале он вызывает
|
||||
`Terrain::stdSetCurrentCamera2(camera)`, сохраняет указатель камеры на время
|
||||
кадра и очищает его перед возвратом. `sendEndOfRender` — отдельный экспорт по
|
||||
RVA `0x13D90`. Эти данные подтверждают только порядок вызовов в кадре: анализ
|
||||
не восстанавливает ABI камеры, матрицы или значения `viewport`. Реализованный
|
||||
путь превью принимает входные данные с матрицей `selector0_words`, полученные через
|
||||
[процедуру захвата нативного кадра](../../tools/native-frame-capture/README.md).
|
||||
|
||||
Receiver-side GOG Terrain evidence refines this contract. `stdSetCurrentCamera2`
|
||||
(RVA `0x4FD40` in Terrain SHA-256
|
||||
`af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead`) queries
|
||||
selector `18` on the supplied object and invokes slot `+12` on that result. It
|
||||
does not store the supplied pointer in `stdGetCurrentCamera2`; that getter
|
||||
returns a Terrain global populated by selector `8` during Terrain initialization.
|
||||
Процедура захвата записывает наблюдавшийся путь миссии и значение
|
||||
`atmosphere_seconds`, если проверка потока, поколения и часов прошла успешно.
|
||||
В превью с фиксированной камерой эта абсолютная фаза расписания используется,
|
||||
если не задан параметр `--atmosphere-seconds`; на всех кадрах чтения сохраняется
|
||||
та же фаза. Явный параметр командной строки имеет приоритет. Эта фаза не равна
|
||||
времени полной симуляции: погода, RNG и другие состояния миссии остаются
|
||||
неизвестны, поэтому она не подтверждает полного совпадения кадра.
|
||||
|
||||
`Terrain.dll!LoadCamera` adds a separate factory-side contract. Its GOG entry
|
||||
at RVA `0x4EBE0` is `__stdcall` with four machine-word arguments, allocates
|
||||
`0x1A4` bytes, calls the constructor at RVA `0x4EC60`, and returns the interface
|
||||
at object offset `+0x134`. The constructor passes arguments 3 and 4 into base
|
||||
initialization at `this + 4`, writes argument 3 to `this + 0x138`, and calls a
|
||||
helper at RVA `0x4CEF0` with arguments 1, 2 and 4 plus `this`. Argument 1 is a
|
||||
mode string: only `REFLECTION` and `REFLECTION_SHIFTED` produce a non-zero mode
|
||||
value at `this + 0x1A0`. This is factory ABI evidence, not a recovered view or
|
||||
projection matrix contract.
|
||||
Анализ принимающей стороны уточняет этот контракт. `stdSetCurrentCamera2`
|
||||
(RVA `0x4FD40` в Terrain с SHA-256
|
||||
`af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead`)
|
||||
запрашивает селектор `18` у переданного объекта и вызывает слот `+12` полученного
|
||||
интерфейса. Указатель не сохраняется в `stdGetCurrentCamera2`: этот геттер
|
||||
возвращает глобальное значение Terrain, установленное селектором `8` при
|
||||
инициализации Terrain.
|
||||
|
||||
## Legacy camera preview path
|
||||
`Terrain.dll!LoadCamera` задаёт отдельный контракт фабрики. Точка входа GOG по
|
||||
RVA `0x4EBE0` использует соглашение о вызовах `__stdcall` и принимает четыре
|
||||
машинных слова, выделяет `0x1A4` байта, вызывает конструктор по RVA `0x4EC60` и
|
||||
возвращает интерфейс по смещению объекта `+0x134`. Конструктор передаёт
|
||||
аргументы 3 и 4 в инициализацию базового объекта по `this + 4`, записывает
|
||||
аргумент 3 в `this + 0x138` и вызывает вспомогательную функцию по RVA `0x4CEF0`,
|
||||
передавая ей аргументы 1, 2 и 4 вместе с `this`. Аргумент 1 — строка режима:
|
||||
ненулевое значение по `this + 0x1A0` дают только `REFLECTION` и
|
||||
`REFLECTION_SHIFTED`. Это свидетельство ABI фабрики, а не восстановленный
|
||||
контракт матрицы вида или проекции.
|
||||
|
||||
`fparkan-game --legacy-camera-capture <json>` consumes the selector-0 transform,
|
||||
the native D3D7 viewport RECT `[left, top, right, bottom]`, near/far planes and
|
||||
field of view. It derives the D3D7 view and clip transform from those inputs,
|
||||
carries the resulting `clip_from_world` matrix into the preview camera, and
|
||||
keeps the view-matrix camera axes directly, so the captured basis, including
|
||||
roll, is not reduced to yaw/pitch. The RECT becomes a physical drawable extent
|
||||
of `right - left` by `bottom - top`. The preview window is fixed to that extent;
|
||||
startup and non-zero resize events reject a physical-size mismatch instead of
|
||||
stretching the captured view. Compare the result with the corresponding
|
||||
`[left, top, right, bottom]` crop of the original PNG. `FreeFlightCamera` is not
|
||||
created in this mode, but redraws still update environment and projected
|
||||
shadows from the captured camera. Before environment updates can emit sound
|
||||
events, the audio listener receives the captured position, forward and up axes;
|
||||
initial world draw sorting uses the same captured position. A phase capture may
|
||||
include an observed mission path and a verified `atmosphere_seconds` value; the
|
||||
latter is used only when no explicit CLI override is supplied. This value pins
|
||||
the atmosphere schedule sample during a fixed-camera comparison while FX still
|
||||
receives real frame time. `simulation_time_seconds`, weather, RNG and complete
|
||||
mission state remain unknown, and a camera/phase match alone does not establish
|
||||
visual parity with a native frame.
|
||||
## Предпросмотр по захвату камеры D3D7
|
||||
|
||||
The preview's sky heading is `atan2(forward.x, forward.y)`, matching the second
|
||||
output calculated at `Terrain.dll` RVA `0x4F9C0`; `CSky` adds π at RVA `0x481C5`
|
||||
when selecting screen-gradient sectors. This mapping is applied only at the sky
|
||||
boundary and does not change `FreeFlightCamera` yaw or movement controls.
|
||||
Matched same-camera, same-phase three-frame captures at phases 56.227 and
|
||||
998.893 showed zero changed pixels before and after this correction; the
|
||||
remaining sky and color mismatch is unresolved, so this source-level match does
|
||||
not establish visual parity.
|
||||
`fparkan-game --legacy-camera-capture <json>` принимает матрицу камеры
|
||||
`selector0_words`, прямоугольник области отображения `viewport` D3D7
|
||||
`[left, top, right, bottom]`, ближнюю и дальнюю плоскости и угол поля зрения.
|
||||
По этим данным превью строит матрицы вида и проекции D3D7, передаёт полученную
|
||||
матрицу `clip_from_world` камере превью и напрямую использует оси камеры из
|
||||
матрицы вида. Поэтому базис захвата, включая крен, не сводится к рысканию и
|
||||
тангажу. Прямоугольник задаёт физический размер области отрисовки:
|
||||
`right - left` на `bottom - top`. Размер окна превью закреплён: если при
|
||||
запуске или после ненулевого изменения окна физический размер не совпадает с
|
||||
заданным, приложение завершает работу, а не растягивает изображение.
|
||||
Сравнивайте результат с фрагментом исходного PNG по прямоугольнику
|
||||
`[left, top, right, bottom]`. В этом режиме `FreeFlightCamera` не создаётся,
|
||||
но при повторной отрисовке обновляются окружение и проецируемые тени для
|
||||
захваченной камеры. До обновления окружения, которое может создавать звуковые
|
||||
события, слушателю задаются захваченные позиция, направление вперёд и верхняя
|
||||
ось; начальная сортировка диапазонов мира использует ту же позицию.
|
||||
|
||||
## Parity risks
|
||||
Захват может содержать наблюдавшийся путь миссии и проверенное значение
|
||||
`atmosphere_seconds`; последнее используется только при отсутствии явного
|
||||
параметра командной строки. Это значение фиксирует фазу расписания атмосферы
|
||||
при сравнении с неподвижной камерой, тогда как FX продолжает получать реальное
|
||||
время кадра. `simulation_time_seconds`, погода, RNG и полное состояние миссии
|
||||
остаются неизвестными, поэтому совпадение камеры и фазы не подтверждает
|
||||
визуального совпадения с нативным кадром.
|
||||
|
||||
`VulkanStaticCamera::from_legacy_d3d7` keeps the D3D7 view and projection
|
||||
reconstruction in `fparkan-render`, then negates the vertical projection term
|
||||
once at the Vulkan adapter boundary. D3D7's top-down viewport places positive
|
||||
NDC Y at the top; the Vulkan swapchain uses a positive viewport height, so the
|
||||
adapter flips NDC Y while the shader preserves `gl_Position`. The generic
|
||||
`from_row_major_view_projection` path remains unchanged; its callers supply
|
||||
Vulkan-ready matrices, as the free-flight camera already does.
|
||||
Для неба превью вычисляет направление как `atan2(forward.x, forward.y)`. Оно
|
||||
совпадает со вторым выходным значением, вычисляемым в `Terrain.dll` по RVA
|
||||
`0x4F9C0`; при выборе сектора экранного градиента `CSky` добавляет π по RVA
|
||||
`0x481C5`. Это преобразование применяется только на границе неба и не меняет
|
||||
рыскание или управление движением `FreeFlightCamera`.
|
||||
|
||||
- x87 precision and rounding;
|
||||
- scalar/SIMD `g_FastProc` differences;
|
||||
- object, batch and transparent primitive order;
|
||||
- depth, cull, alpha test and blend transitions;
|
||||
- mip-skip, palette and Page coordinates;
|
||||
- material fallback and phase selection;
|
||||
- RNG sequence for FX and atmosphere;
|
||||
- device capability fallback;
|
||||
- simulation time quantization.
|
||||
## Ограничения точного совпадения
|
||||
|
||||
Для отладки нужен deterministic frame capture: camera state, visible object IDs,
|
||||
draw-item list, pipeline keys, matrices и hashes промежуточных buffers.
|
||||
`VulkanStaticCamera::from_legacy_d3d7` выполняет восстановление вида и проекции
|
||||
D3D7 в `fparkan-render`, а затем один раз меняет знак вертикального члена
|
||||
проекции на границе адаптера Vulkan. В области отображения D3D7 положительная
|
||||
координата NDC Y направлена вверх экрана; Vulkan использует положительную высоту
|
||||
области отображения, поэтому адаптер меняет знак NDC Y, а шейдер сохраняет
|
||||
`gl_Position`. Общий путь
|
||||
`from_row_major_view_projection` не меняется: вызывающие его функции передают
|
||||
матрицы, уже подготовленные для Vulkan, как и камера свободного полёта.
|
||||
|
||||
- точность и округление x87;
|
||||
- различия scalar/SIMD в `g_FastProc`;
|
||||
- порядок объектов, пакетов и прозрачных примитивов;
|
||||
- переходы состояний проверки глубины, отсечения граней, альфа-теста и смешивания;
|
||||
- пропуск mip-уровней, палитра и координаты Page;
|
||||
- запасной материал и выбор фазы;
|
||||
- последовательность RNG для FX и атмосферы;
|
||||
- переход на запасной набор возможностей устройства;
|
||||
- квантование времени симуляции.
|
||||
|
||||
Для отладки требуется детерминированный захват кадра: состояние камеры,
|
||||
идентификаторы видимых объектов, список элементов отрисовки, ключи конвейера,
|
||||
матрицы и хэши промежуточных буферов.
|
||||
Reference in new issue
Block a user