Skip to content

[macOS] Fix Metal RHI 3D viewer crashes and enable qtAliceVision plugins#3030

Open
NeverGET wants to merge 10 commits intoalicevision:developfrom
NeverGET:feature/macos-metal-3d-viewer
Open

[macOS] Fix Metal RHI 3D viewer crashes and enable qtAliceVision plugins#3030
NeverGET wants to merge 10 commits intoalicevision:developfrom
NeverGET:feature/macos-metal-3d-viewer

Conversation

@NeverGET
Copy link
Copy Markdown

@NeverGET NeverGET commented Mar 7, 2026

Summary

  • Fix Metal RHI 3D viewer crashes on macOS caused by missing vertexNormal attributes in custom Qt3D geometries
  • Compute flat normals via dFdx/dFdy derivatives instead of requiring normals as vertex attributes in SphericalHarmonics shaders
  • Add ensureNormals() to dynamically patch loaded meshes (OBJ/PLY) that lack normals
  • Add OpenGL 3.2 Core Profile fallback shader techniques for broader compatibility
  • Fix textured material lighting (high ambient from MTL files was washing out textures)
  • Add QML plugin path discovery for qtAliceVision, SfmDataEntity, and DepthMapEntity
  • Add macOS support to setupEnvironment() (DYLD paths, Metal RHI backend, Qt plugin path guards)
  • Fix cgroup CPU detection crash on non-Linux platforms
  • Add groupDesc backward compatibility for AliceVision node descriptors

Acknowledgments

Huge thanks to @music-dsp-collection for the incredible work on MTL-AliceVision (alicevision/AliceVision#2019) — bringing Metal GPU support and the complete macOS build pipeline to AliceVision is a massive achievement. And to the entire @alicevision team for building such an amazing open-source photogrammetry ecosystem. This PR is a small contribution building on top of their foundational work to help get the Meshroom 3D viewer running smoothly on macOS.

Context

While testing Meshroom on macOS 26.3 (Apple Silicon M4 Max, Mac15,6) with the MTL-AliceVision bundle from PR alicevision/AliceVision#2019, we found that the 3D viewer crashed due to Metal's strict vertex descriptor validation when geometries lacked normal attributes that built-in Qt3D materials expect.

Root cause: Metal RHI validates that all vertex shader inputs (layout(location = N) in ...) are satisfied by the geometry's vertex descriptor. When a shader declares vertexNormal but the geometry only provides vertexPosition, Metal's pipeline state creation fails, crashing the application.

Fixes applied:

  1. SphericalHarmonics shaders: Remove vertexNormal input entirely; compute flat normals from dFdx/dFdy derivatives of world position in the fragment shader
  2. Custom geometries (Grid3D, BoundingBox, Locator3D): Add default (0, 1, 0) normal attributes
  3. Loaded meshes: New Scene3DHelper.ensureNormals() dynamically adds normals to geometries missing them
  4. OpenGL fallback: GLSL 330 Core techniques so shaders work on both Metal RHI and OpenGL backends
  5. Platform support: macOS-specific library path handling, Metal RHI default, cgroup fix, Qt plugin path guards

Test Plan

  • Launch Meshroom on macOS with Metal RHI (no QT3D_RENDERER override needed)
  • Enable 3D viewer — no crash
  • Load mesh from Texturing node — renders correctly with proper lighting
  • Resize window — no crash
  • Switch render modes (Solid, Wireframe, Textured, SH)
  • Verify qtAliceVision plugin loads (no "Missing plugin" warning)
  • Verify EXR textures load via QtAliceVisionImageIO
  • Grid, BoundingBox, Locator render without crash
  • All pipeline nodes execute correctly (camera init, feature extraction, etc.)

Tested on

🤖 Generated with Claude Code

NeverGET and others added 9 commits March 7, 2026 20:40
Metal RHI strictly validates that vertex shader inputs match the vertex
descriptor provided by the geometry. The SphericalHarmonics shaders
declared a vertexNormal input, but custom Qt3D geometries (Grid3D,
BoundingBox, Locator3D) and some loaded meshes don't provide normal
attributes, causing Metal pipeline creation to fail with a crash.

Instead of requiring normals as a vertex attribute, compute flat face
normals in the fragment shader using dFdx/dFdy screen-space derivatives
of the world position. This produces correct lighting for flat-shaded
geometry and works regardless of whether the mesh provides normals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Built-in Qt3D materials (PhongMaterial, DiffuseSpecularMaterial) expect
a vertexNormal attribute in the vertex descriptor. On Metal RHI, if a
geometry lacks this attribute, the render pipeline state creation fails
with a crash because Metal strictly validates that all shader inputs
are satisfied by the vertex descriptor.

Add default upward-facing (0, 1, 0) normal attributes to:
- Grid3D.qml (dynamic count matching grid vertices)
- BoundingBox.qml (24 vertices)
- Locator3D.qml (6 vertices)

These normals ensure Metal pipeline compatibility while maintaining
correct visual appearance for these helper geometries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Meshes loaded via SceneLoader (OBJ, PLY, etc.) may lack normal
attributes. When these meshes are rendered with built-in Qt3D materials
that require vertexNormal, Metal RHI crashes due to missing vertex
descriptor entries.

Add Scene3DHelper.ensureNormals(entity) that traverses all QGeometry
children of a loaded entity and adds default (0, 1, 0) normal
attributes to any geometry missing them. Call this method in
MediaLoader's sceneLoaderPostProcess before material setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OpenGL 3.2 Core Profile technique alternatives to the existing
RHI techniques in WireframeEffect and SphericalHarmonicsEffect. This
provides shader compatibility on platforms where Qt3D uses the OpenGL
backend instead of RHI/Metal.

New shader files:
- SphericalHarmonics_gl.vert/frag: GLSL 330 versions using uniforms
  instead of UBO layout qualifiers
- robustwireframe_gl.vert/geom/frag: GLSL 330 wireframe rendering
  with geometry shader for barycentric coordinate computation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Override the textured material's ambient, shininess, and specular
properties with low fixed values instead of inheriting from the
loaded mesh's MTL material properties. Many OBJ files include high
ambient values that wash out textures when viewed in the 3D viewer.

Using low ambient (alicevision#111), no specular (#000), and minimal shininess
(1.0) ensures textures are displayed with proper diffuse-only lighting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add QML import paths for PySide6's bundled QML modules and the
AliceVision bundle's PlugIns directory. This enables the QML engine
to discover and load qtAliceVision, SfmDataEntity, and DepthMapEntity
QML plugins that provide camera visualization, SfM data overlay,
and depth map rendering in the 3D viewer.

The PySide6 QML path ensures Qt3D and QtQuick.Scene3D modules are
found, while the AV_BUNDLE/PlugIns path provides the AliceVision-
specific visualization plugins.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Guard QT_PLUGIN_PATH and QML2_IMPORT_PATH setup behind directory
  existence checks. On macOS with PySide6, these directories may not
  exist in the standard locations and setting invalid paths causes
  plugin loading failures.

- Add macOS-specific DYLD_FALLBACK_LIBRARY_PATH handling (analogous
  to LD_LIBRARY_PATH on Linux) so AliceVision framework libraries
  can be found at runtime.

- Use Metal as the default RHI backend on macOS (QSG_RHI_BACKEND=metal)
  via setdefault so it can be overridden, while keeping OpenGL as
  the default on other platforms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The cgroup CPU count detection reads /proc/self/cgroup which only
exists on Linux. On macOS and Windows, this causes a crash when
Meshroom tries to determine available CPU cores for task parallelism.

Add an early return using os.cpu_count() on non-Linux platforms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Some AliceVision node descriptors from the MTL-AliceVision bundle
use the older 'groupDesc' parameter name instead of 'items' in
GroupAttribute constructors. Add backward compatibility by accepting
'groupDesc' as a deprecated alias and defaulting positional params
to allow keyword-only usage patterns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@NeverGET NeverGET marked this pull request as ready for review March 7, 2026 17:46
@philippremy
Copy link
Copy Markdown

This is AWESOME! I ran into all these issues and did some very dirty hacking to get a bare minimum of it working 😅.
That would have been a follow-up project for me eventually but honestly: I am really not into Qt and QML... you are a lifesaver! I'll make sure to do some testing the following days ^^.
So a big thank you for looking into this!!!

@NeverGET
Copy link
Copy Markdown
Author

NeverGET commented Mar 9, 2026

You're welcome, BTW I bundled the app and using daily 😄.
I didnt test all the features in the app, i am still investigating the app, if you have a test list for it, i can try on and keep fixing the issues for MacOS

Comment on lines -98 to +100
ambient: root.ambient
shininess: root.shininess
specular: root.specular
ambient: "#111"
shininess: 1.0
specular: "#000"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What's the reason to change that?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Actually the mesh preview is looking a bit phased off, like whiteish. I tried to make it look like full saturated colour but it didn't worked either and I was feeling very happy about the app is working, I directly go into PR.

Tldr; it just a mess I forgot to revert

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 20, 2026

Codecov Report

❌ Patch coverage is 19.04762% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.78%. Comparing base (9d79c95) to head (6bd7eb7).
⚠️ Report is 102 commits behind head on develop.

Files with missing lines Patch % Lines
meshroom/__init__.py 13.33% 13 Missing ⚠️
meshroom/core/cgroup.py 0.00% 3 Missing ⚠️
meshroom/core/desc/attribute.py 66.66% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (19.04%) is below the target coverage (70.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3030      +/-   ##
===========================================
- Coverage    82.92%   82.78%   -0.15%     
===========================================
  Files           71       71              
  Lines         9546     9565      +19     
===========================================
+ Hits          7916     7918       +2     
- Misses        1630     1647      +17     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@@ -196,12 +196,15 @@ def matchDescription(self, value, strict=True):
class GroupAttribute(Attribute):
""" A macro Attribute composed of several Attributes """
@deprecated.depreciateParam("group", "Param 'group' on {name} should not be used anymore. Please use 'commandLineGroup' instead")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
@deprecated.depreciateParam("group", "Param 'group' on {name} should not be used anymore. Please use 'commandLineGroup' instead")
@deprecated.depreciateParam("group", "Param argument 'group' on {name} should not be used anymore. Please use 'commandLineGroup' instead")
@deprecated.depreciateParam("groupDesc", "GroupAttribute argument 'groupDesc' on {name} should not be used anymore. Please use 'items' instead")

@fabiencastan fabiencastan added this to the Meshroom 2026.1.0 milestone Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants