FERRETGame engine over Babylon.js
Ferret

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#

  1. Shoot the original from a camera set (reference/ue-parity.md): tools/ue-export/ue/capture_parity.py in 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).
  2. Shoot Ferret from the same cameras, stitch side by side, look at every view.
  3. Name the wrong thing: scene.pick gives mesh and material (it skips thin instances: list meshes whose bounds cover the point too).
  4. Switch one source at a time (sun, ambient, environmentIntensity, the normal map, the mesh itself) and read the pixel.
  5. Compare a wrong and a right mesh: the compiled defines (sourceMesh.subMeshes[0].effect.defines: LIGHTCOUNT, HEMILIGHT, REFLECTION), normals against winding, determinant, UVs.
  6. Fix in the right layer: the engine (@ferret/assets, @ferret/levels) for a general cause, postprocess.mjs for an export defect, the level's environment override for by-eye light.
  7. 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.direction facing down with ambient.ground the 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/levels with signature and doc comment
  • reference/api-levels-2.md — every export of @ferret/levels with signature and doc comment
  • reference/api-assets.md — every export of @ferret/assets with signature and doc comment
  • reference/api-assets-2.md — every export of @ferret/assets with signature and doc comment
  • reference/commands.md — 39 commands of these packages with their arguments