Skip to content

OMSI 2 illuminated material rendering compatibility - #2942

Merged
thibautgnt merged 4 commits into
openOMSI-org:mainfrom
dev-Younte:pr/illuminated-material-coverage
Oct 19, 2026
Merged

thibautgnt merged 4 commits into
openOMSI-org:mainfrom
dev-Younte:pr/illuminated-material-coverage

Conversation

@dev-Younte

@dev-Younte dev-Younte commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

What changes for the player?

Illuminated instruments using a fully transparent diffuse placeholder now show their night texture's artwork and silhouette. This restores missing gauge needles and circular rims in Classic, Vanilla+ and Enhanced rendering.

How to test

Automated verification (primary; no vehicle mod required)

Run the Rust library tests and synthetic GPU regression first. Neither command requires the Elec City Town mod or its vehicle resources. Vehicle files, textures and models are not included in this PR and are not needed by these automated checks.

cargo test --locked -p omsi-render -p omsi-scene --lib
cargo test --locked -p omsi-render --lib a_clear_lamp_uses_its_active_night_maps_coverage -- --ignored

The first command runs the renderer and scene library tests, including shader snapshots, uniform validation and GLSL generation. The second explicitly runs the otherwise ignored synthetic GPU regression and requires a graphics adapter; its geometry and textures are generated by the test.

The GPU test covers 11 cases in each of Classic, Vanilla+ and Enhanced (33 cases total): coloured/white artwork, an RGB night map with no alpha, inactive/missing/transparent night maps, ordinary diffuse coverage, alpha-test/opaque materials and explicit masks. Four non-ignored scene-side CPU tests protect eligibility, dynamic-texture exclusions, selected-map alpha metadata, repaint substitution and item inheritance. It verifies renderer-level coverage handling, not vehicle-loader integration or a full vehicle run.

Optional in-game verification

If you already have OMSI 2 and a separately installed Elec City Town (LFELEC_TOWN_PIEV.bus), you can additionally check the actual vehicle:

  1. Load the driver's view and switch on the main electrical supply. The pointers and circular rims should show the original white artwork, as in OMSI 2.
  2. Drive and check pointer movement. Switch the supply off/on; the unpowered material should remain clear.
  3. Repeat in Vanilla and Enhanced; check an unaffected vehicle such as MAN D86.

This optional check is not a prerequisite for running the automated tests above. The scope of the existing combined-build in-game feedback is documented separately below.

Screenshots

These synthetic renderer-level comparisons use identical geometry, UVs, camera, lighting, clear diffuse texture and white night artwork on freshly compiled upstream and PR 1 alone. The patched fixture enables the new night_alpha selector for the eligible material. This isolates the rendering change; it does not exercise the vehicle loader or constitute a PR-1-only vehicle run. No original vehicle assets are used.

Rendering path Before: upstream ccc79522 After: PR 1 cfad33be
Vanilla+ upstream-vanilla-plus pr1-vanilla-plus
Enhanced upstream-enhanced pr1-enhanced

The owner manually confirmed white pointers/rims and normal N/D/R operation on Windows using a combined 0.3.37 Debug build with this fix and a separate visibility proposal. Earlier MAN D86 renders also passed in that combined build. These are not PR-1-only vehicle runs or evidence that this PR fixes gear overlap.

What does this change, and why?

The affected material uses an entirely transparent diffuse picture (lcd_needle.tga) and stores its visible artwork and alpha in the night picture (lcd_needle_on.tga). OMSI 2 displays the illuminated artwork. openOMSI adds the night RGB but retains the zero diffuse alpha, making the geometry invisible during blending.

For loaded static blended vehicle materials in the existing fully-clear cover classification, coverage now comes from the active night texture only when that map loads successfully and the texture loader reports alpha. RGB night maps retain diffuse coverage. DXT1 follows the loader's actual transparent-index detection rather than a format-name blacklist. The GPU texture and alpha metadata use the same repaint-substituted path and are inherited together by material items. A spare material flag selects a shared helper in both shading paths, without changing the uniform layout. Material switching preserves the unpowered state.

Explicit transmaps retain priority. Ordinary coverage, alpha-tested/opaque materials, generated text/script textures, changing textures, mirrors, rain films and freetex retain their current rules. There are no vehicle-specific conditions or dependencies on the separate visibility proposal.

Changed files:

  • omsi-scene/src/vehicles.rs, vehicle_materials.rs: select coverage for base/switched materials.
  • omsi-scene/src/vehicles/night_coverage.rs: shared eligibility/map helpers and four non-ignored CPU regression tests.
  • omsi-render/src/resources/materials.rs: encode the flag and enforce coverage guards.
  • omsi-render/src/shaders/scene/02_bindings.wgsl, 09_vanilla.wgsl, and shaders/enhanced/04_shade.wgsl: apply night alpha.
  • omsi-render/src/shaders.rs: update intentional snapshots.
  • omsi-render/src/tests.rs, tests/night_coverage.rs: GPU regressions.

All paths above are under crates/.

Initial validation of cfad33be against upstream ccc795229068ae2764ac35897aaeb80a3c9882ab, Windows x64 GNU:

  • Fresh PR-1-only library tests: render 117 passed / 46 ignored; scene 152 passed / 4 ignored. Shader snapshots, uniform validation and GLSL generation pass. Render, scene and simulation were recompiled to exclude shared-cache reuse.
  • GPU: all 30 regression cases and the separate upstream/PR1 screenshot comparisons pass.
  • PR-1-only Release game build passes (cargo build --locked --release -p omsi-app --bin openomsi); a waited --version process exits 0.
  • Clippy completes without errors, with warnings in existing code. Full rustfmt fails on both this branch and upstream for the same 835 file paths; the new regression test passes standalone rustfmt.
  • Size/architecture guards, whitespace and scope checks pass. The commit contains only 9 Rust/WGSL files, each below 1 MB.

Review follow-up validation (bc2f7274)

The review revision was validated independently of the variable proposal, against upstream main at 1f6ff3890038c38cbf95c499f1ae11f4268fcc82 (Windows x64 GNU; local checks on 2026-10-18):

  • Four new non-ignored scene CPU tests cover alpha/RGB/missing night maps, clear versus ordinary/missing diffuse, transmap priority, freetex/mirror/rain/text/script exclusions, selected-map alpha metadata, repaint substitution and item inheritance.
  • Renderer library: 117 passed / 46 ignored; scene: 156 passed / 4 ignored; texture loader: 87 passed, including DXT1 transparency detection. Shader snapshots, uniform validation and GLSL generation pass.
  • The explicitly run GPU regression passes 33 cases across Classic, Vanilla+ and Enhanced, including an RGB night map whose sampled alpha is 1. CPU tests protect selection of the flag; the GPU test verifies rendering with that selected flag and is not a vehicle-loader integration test.
  • Separate PR-1-only Debug and Release builds succeed, and both --version invocations exit 0. Debug still captures of the actual TGA instruments retain white pointers/rims in Vanilla and Enhanced. These are PR-1-only still captures, not a new driving/animation test or combined-build validation. Release rendering remains unsuccessful as described below.
  • Scoped Clippy completes without errors, with existing warnings. The new scene/GPU modules pass standalone default rustfmt. Full-workspace rustfmt reports the same 850 existing file paths as unmodified upstream; existing source layout was retained to avoid unrelated reformatting.
  • Size/architecture and whitespace guards pass. The follow-up changes 5 files; the full PR now contains 10 Rust/WGSL files (+508/-20), including the new CPU module. No vehicle resources, screenshots, binaries, local paths or variable-compatibility code are committed.

static_diffuse is shared, base/item text/script exclusions are explicit, snapshot numeric separators are retained, and the renderer test module is alphabetized. The earlier screenshot comparisons remain at their original revisions. Full-workspace tests and new platform CI are separate from these scoped local results.

What could break?

Other add-ons may use this pattern; exhaustive vehicle compatibility and Metal/mobile remain untested locally. Official CI results are tracked separately in the Checks tab; scoped local results do not establish a full-workspace pass. Clear slots disabling depth testing/writing remain outside the existing cover classification. Physics, inputs, saves and network protocols are unchanged.

Earlier full-workspace tests hit a GNU/LLD duplicate-resource link error. Excluding the app yielded 2,325 passed / 1 failed / 101 ignored; the codepage failure also reproduces on unchanged upstream on this Korean Windows host.

Release rendering of the review follow-up was tested and still fails locally: a fresh debugger run stops on a renderer-pipeline worker in repeated D3DCompiler_47.dll frames. A retained unmodified-upstream control at the earlier base shows the same recursion pattern (the update to that earlier base was README-only). An unpatched Release runtime control at 1f6ff389 was not rerun. The internal FXC/backend cause remains unconfirmed and is not fixed here. Successful compilation and --version are not renderer-startup passes.

Checklist

  • cargo test --workspace and cargo build --release pass
  • The pull request contains a single change
  • Before/after screenshots are in the description if anything changes on screen
  • New or changed interface texts are in crates/omsi-app/locales/app.yml, in every language I can (no text changes)
  • Online play, saves, settings and mods made for the previous release still work, or the description says what changes
  • No original OMSI 2 content and no file of a megabyte or more in the commits

Use the active night texture alpha only for static, fully clear blended
vehicle materials. Preserve explicit masks and generated texture coverage
and cover the shader paths with GPU regressions.
@dev-Younte
dev-Younte marked this pull request as ready for review October 18, 2026 06:28

@thibautgnt thibautgnt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dev-Younte, nicely scoped. The synthetic before/after captures across all three paths make the change easy to judge, the flag reuses a spare bit without touching the uniform layout, and leaving explicit transmaps alone is the right call. One guard before merge.

Blocking

  1. A night map without an alpha channel turns the whole clear quad opaque. night_coverage (crates/omsi-scene/src/vehicles.rs:1260) only checks that a night texture exists, and the shader then takes sample_nightmap(uv).a as coverage (shaders/scene/02_bindings.wgsl:212). A 24-bit BMP/JPG or DXT1 night map samples alpha 1 everywhere, so a clear lamp, or an invisible cover that writes depth to hide what's behind it, goes from invisible to an opaque rectangle around its artwork. Plain RGB night maps are very common in OMSI content. Your case (lcd_needle_on.tga) has real alpha. Please also require that the night texture has an alpha channel, as the transmap path already does with self.textures.has_alpha(...), or show that the original also makes such a quad opaque.

Smaller

  • vehicles.rs:1092 and :1156 build the same tex.is_some() && !freetex && !rain_layer && mirror_index(&tex_name).is_none() twice: compute it once as let static_diffuse = …; and add text_item/script_item for the item.
  • shaders.rs:59-60: please keep the _ separators in the snapshot numbers (124_812, 0xb4bf_f042_faf9_df38) like the lines you replaced.
  • tests.rs: mod night_coverage; goes in alphabetical order, before mod prepass_reach;.
  • No CPU test covers the slot rules (transmap, freetex, mirror and text/script exclusions); the GPU test is #[ignore] and never runs in CI. A small scene-side unit test on night_coverage(...) would protect them.

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Test builds for 1ca8825

Platform Download
Android (arm64) android.zip
Linux x64 (game and dedicated server) linux-x64.zip
macOS (Apple silicon) macos-arm64.zip
Windows x64 (game and dedicated server) windows-x64.zip
  • Unpack the download into a new folder, not over your openOMSI. The launcher shows the version as ...-pr2942, and a test build is never updated. It shares your settings and OMSI 2 folder; mods you installed into your openOMSI folder are only seen when you unpack it into a copy of that folder.
  • Android: the download holds an APK that installs as a separate app, openOMSI PR OMSI 2 illuminated material rendering compatibility #2942, beside the release, and shares its openOMSI folder.
  • What to try is under How to test in the description. Please comment with what you found and the version the launcher shows.
  • The links work for 14 days after the build.

@dev-Younte

dev-Younte commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

Thank you for the careful review, @thibautgnt. Addressed in bc2f727, with the original commit retained and current main merged without rewriting history.

The missing alpha guard was a real regression risk. Night coverage now requires a successfully loaded night map and self.textures.has_alpha(...). RGB BMP/JPEG maps retain diffuse coverage. DXT1 follows the existing loader's actual transparent-index detection, so opaque BC1 is excluded while punch-through alpha remains eligible. The GPU texture and alpha metadata use the same repaint-substituted path and are inherited together by material items.

  • Added four non-ignored scene CPU tests for alpha/RGB/missing maps, clear/ordinary diffuse, explicit transmaps, freetex, mirrors, rain, text/script textures, repaint substitution and item inheritance. Existing coverage/exclusion rules are preserved.
  • Compute static_diffuse once and apply base/item text/script exclusions. Restored snapshot numeric separators and alphabetized the test module. New test/helper modules pass default rustfmt; existing source layout was retained, and full rustfmt reports the same 850 pre-existing paths as upstream.
  • Local results: render 117, scene 156, texture 87 passed; the explicitly run GPU regression passes 33 cases across Classic, Vanilla+ and Enhanced, including RGB night coverage. Clippy completes without errors (existing warnings). Separate Debug/Release builds succeed; PR-1-only Debug still captures retain the white TGA pointers/rims in Vanilla and Enhanced.

Release rendering still fails locally in repeated D3DCompiler_47.dll frames. A retained earlier unmodified-upstream control has the same recursion pattern; the latest unpatched-main Release runtime control was not rerun. Build success is not a Release rendering pass. Full-workspace validation is not claimed; official CI is tracked separately in Checks.

The description has been updated with the scoped results and limits, preserving the existing screenshots. The new GitHub runs currently await maintainer approval (action_required), rather than reporting a test failure. Please take another look when convenient.

@thibautgnt thibautgnt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dev-Younte, that's a thorough follow-up. The alpha guard now works like the transmap path (the same repaint-substituted name and self.textures.has_alpha(...), and an item without its own night map takes the base map with its alpha flag). static_diffuse is computed once and the text/script exclusions apply to the item, the snapshot separators are back, mod night_coverage; is in order, and the four new scene-side tests cover the slot rules. Merges cleanly with main. Approving.

Smaller (no need to hold the merge)

  • crates/omsi-scene/src/vehicles/night_coverage.rs:70: the "missing night" row has the same inputs as "RGB night" above it, so it doesn't test a missing map (that case is covered by night_map_metadata_follows_repaint_substitution_and_missing_items). Drop it or relabel it.
  • crates/omsi-render/src/tests/night_coverage.rs: the new RGB case runs with enabled: false, so it's the same as the disabled case below it; the scene guard is what protects RGB maps.

@thibautgnt thibautgnt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @dev-Younte, I have to take my approval back after running it. On macOS (Apple M4 Pro, Metal) this branch makes Apple's shader compiler crash on the scene pipeline at 4x MSAA:

ERROR omsi_render::gpu::open] Apple M4 Pro: the renderer's pipelines failed (4x MSAA): Validation Error
  In Device::create_render_pipeline, label = 'omsi'
  Internal error in ShaderStages(VERTEX | FRAGMENT) shader: new_render_pipeline_state: NSError { code: 2,
  localizedDescription: "Compilation failed due to an interrupted connection: XPC_ERROR_CONNECTION_INTERRUPTED. This error occurred after multiple retries.", domain: "AGXMetalG16X" }

The game then falls back to 1x MSAA, so every Mac player would lose anti-aliasing. It's reproducible: 18 such errors in each run of scripts/bench-window.sh (plain and Enhanced) with main + this PR alone, none with main. The GPU tests pass because they don't build the 4x MSAA scene pipeline.

Since the only shader change is the night coverage path (night_coverage in 02_bindings.wgsl and its use in the vanilla and enhanced shading), that's very likely what trips the Metal compiler: it may be the extra sample_nightmap in the alpha path, or a branch on the new flag bit. Could you try computing the coverage from the night sample the shader already takes (one texture read, no second call), and check it on Metal at 4x MSAA? If you don't have a Mac, tell me and I'll test a new commit.

Share each shading path’s night-map sample between coverage and lighting. Preserve the material flag, alpha guards, transmap precedence and uniform layout. Exercise production 1x/4x scene pipelines and actual multisampled render targets, and replace redundant test rows with fractional-alpha coverage.
@dev-Younte

dev-Younte commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor Author

Thank you, @thibautgnt. Follow-up 1ca8825 reuses one night-map sample for coverage and lighting in both shading paths. The coverage helper now receives the sampled alpha instead of performing another texture read. Vehicle/terrain UVs, lighting factors, the alpha/RGB guard, repaint metadata, item inheritance, explicit transmaps and dynamic-material exclusions are preserved; the Rust uniform layout is unchanged.

On this Apple M1 Pro, macOS 27.2, Metal, the original bc2f7274 also passes at 4x, so I could not reproduce your M4 Pro compiler crash. These results do not establish that the M4 Pro issue is fixed.

  • With Metal API Validation enabled, the production renderer passes 33 cases at 1x and 33 at 4x across Classic, Vanilla+ and Enhanced. The new 4x test checks actual colour/depth texture sample counts and pixel readback, and fails if the renderer falls back to 1x.
  • bench-window.sh completed its default 110-second plain and Enhanced runs on main (866c60de), the original PR and this revision: all six retained 4x MSAA, with no pipeline/XPC error or 1x fallback. Debug and Release builds pass; the Release executable also completed both modes at 4x with Metal API Validation enabled.
  • Local library tests: render 117, scene 156, texture 87. The full Mac workspace run passes 2,649 tests, 0 failures, 105 ignored; additional renderer/scene regressions also pass. Windows runtime was not retested.

I also removed the duplicate CPU row and replaced the redundant disabled RGB GPU row with a fractional-alpha blending case; RGB eligibility remains protected by the scene tests.

Could you please retest this commit on your M4 Pro, including plain/Enhanced 4x MSAA? The targeted check is:

MTL_DEBUG_LAYER=1 RUST_LOG=omsi_render=info cargo test --locked -p omsi-render --lib night_coverage -- --ignored --nocapture --test-threads=1

The new official workflows currently await maintainer approval (action_required); I am not reporting them as passed.

@dev-Younte

Copy link
Copy Markdown
Contributor Author

One additional detail for reproducibility: here is the exact hardware and software configuration used for my macOS Metal tests.
Test environment

  • Model: MacBook Pro (M1 Pro)
  • CPU: 8-core CPU
  • GPU: 14-core GPU
  • Memory: 16 GB unified memory
  • Storage: 512 GB SSD
  • OS: macOS 27.2 Developer Beta 4 (build 26B5112a)
  • Graphics backend: Apple Metal
    Since this is an M1 Pro running a developer beta, both the GPU architecture and macOS/Metal software environment may differ from your M4 Pro setup. I thought it would be useful to document the exact configuration for comparison.
    As noted above, I could not reproduce the 4x MSAA compiler failure on this system, including with the previous PR revision.

@thibautgnt thibautgnt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @dev-Younte, and thanks for the thorough Metal testing on your M1 Pro. The new commit does exactly what I asked: one night-map read now feeds both the coverage and the lighting, in Vanilla and in Enhanced, and night_coverage is a plain select on the alpha it's given. The UVs and conditions are unchanged, terrain light map path included, and the new 4x MSAA GPU test checking the targets' real sample counts covers the gap I pointed out.

I reran scripts/bench-window.sh (plain and Enhanced) on the Apple M4 Pro with main + this PR: no pipeline errors and 4x MSAA kept in both modes. Approving.

@thibautgnt
thibautgnt merged commit 8f40e45 into openOMSI-org:main Oct 19, 2026
12 checks passed
@thibautgnt

Copy link
Copy Markdown
Contributor

Merged, thanks @dev-Younte! Illuminated instruments now look as in OMSI 2, and the single night-map read keeps Metal happy at 4x MSAA. Thanks for the careful testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants