A ported level that looks wrong
Skill ferret-unreal-level-look · download all skills · SKILL.md
When to use#
Black walls or posters, one floor piece darker than the next, red smears on pillars, metal like coal, tan instead of cream, everything too bright; or any parity check of a port against Unreal.
Rule one#
Find the cause before changing anything. Stacked guesses made a hall darker with every round and hid which change did what. Each symptom so far had one concrete cause (reference/ue-level-look.md).
Steps#
- Shoot the original from a camera set (
reference/ue-parity.md):tools/ue-export/ue/capture_parity.pyin the running game, one shots folder per level. Without it you cannot tell a bug from the original (the far pillars really are red brick). - Shoot Ferret from the same cameras, stitch side by side, look at every view.
- Name the wrong thing:
scene.pickgives mesh and material (it skips thin instances: list meshes whose bounds cover the point too). - Switch one source at a time (sun, ambient,
environmentIntensity, the normal map, the mesh itself) and read the pixel. - Compare a wrong and a right mesh: the compiled defines (
sourceMesh.subMeshes[0].effect.defines:LIGHTCOUNT,HEMILIGHT,REFLECTION), normals against winding, determinant, UVs. - Fix in the right layer: the engine (
@ferret/assets,@ferret/levels) for a general cause,postprocess.mjsfor an export defect, the level's environment override for by-eye light. - Reshoot all views; write what matches and what differs into the port plan.
Causes found so far#
- Instanced meshes drawing with stale lights or shaders (sources out of the scene): fixed in
AssetCache; if back, compare defines. - A tile without the baked light (stale defines after a plugin was added): fixed in
AssetCache; compare the define strings, not the fields. - Baked light in the mirror image of the level:
bake-gi --mirror-x; the grid must cover the level's bounds. - Floors too bright with baked light: the reflection cube's diffuse light counted twice (fixed: with probes the cube only reflects); bloom is
environment.post. - Retune after every fix: earlier numbers were tuned against the fault.
- Baked lamps eating every light slot:
--no-lights. - Mirrored nodes: own mesh, winding and normals reversed by
postprocess.mjs. - Metal black indoors:
environment.reflection. - World-aligned materials smeared:
ue/materials.py+--world-aligned. - 16-bit source textures are linear: encode to sRGB.
- Helpers hidden in game, screens black until a video plays.
- Flat bright interior: baked light; until it is ported, sun down and
environment.ambient.directionfacing down withambient.groundthe floor colour, in the level's override.
Check afterwards#
Every parity view matches in layout and materials, light is close, and the remaining differences are written down with reasons.
What usually goes wrong#
- Blaming the browser: "only in Edge" was load order.
- Tuning light to hide a material bug, or the reverse.
- Fixing one view and not reshooting the others.
- A capture launcher that clears another level's shots, or runs with an empty script path.
Files#
reference/ue-level-look.md— Symptoms of a wrong-looking ported level (black or dark surfaces, smeared materials, wrong colours, flat light) with their causes and fixes, and how to find the cause instead of guessing.reference/ue-parity.md— Comparing a ported level with the Unreal original from the same cameras: the camera set, the axis mapping, taking the Unreal shots in the running game, taking the Ferret shots, and reading the differences.reference/api-levels.md— every export of@ferret/levelswith signature and doc commentreference/api-levels-2.md— every export of@ferret/levelswith signature and doc commentreference/api-assets.md— every export of@ferret/assetswith signature and doc commentreference/api-assets-2.md— every export of@ferret/assetswith signature and doc commentreference/commands.md— 39 commands of these packages with their arguments