Link Search Menu Expand Document

OCCT visualization → Metal: research findings

Research-only document scoping what it would take to render OCCT geometry on Apple’s Metal API, and which of three concrete paths makes the most sense for the OCCTSwift / OCCTSwiftViewport stack.


TL;DR

Three real paths exist; one is already deployed.

  • Path A. Full TKMetal driver port (replace TKOpenGl with a new Graphic3d_GraphicDriver subclass). Multi-year effort, high maintenance burden, but full AIS surface fidelity and visionOS-native.
  • Path B. Mesh-extraction + native Metal, which is what OCCTSwiftViewport already does today. Working now on macOS / iOS, no OCCT visualization toolkit dependency. Doesn’t give you AIS_InteractiveContext semantics (selection→topology, manipulators, dimensions).
  • Path C. AIS-bridge layer on top of Path B. Keep OCCT visualization off in the xcframework; build the high-value AIS-equivalent functionality (selection-from-topology, manipulator widgets, dimension annotations) as a Swift layer over OCCTSwiftViewport’s existing Metal renderer. ~80% of AIS value at ~10% of TKMetal effort.

Recommendation: don’t port TKOpenGl to TKMetal. Extend Path B with Path C. Visualization stays out of the OCCTSwift xcframework; the Metal rendering surface stays in OCCTSwiftViewport; new AIS-equivalent features become Swift code on top.


OCCT visualization architecture today

OCCT’s visualization is layered across three toolkits, each in Sources/Visualization/ of the OCCT tree:

Toolkit Layer Role
TKV3d High-level AIS_InteractiveContext, AIS_Shape, AIS_Trihedron, AIS_Manipulator, etc. application-facing object model.
TKService Mid-level Platform-independent primitive arrays (points, segments, triangles, fans), graphic structures, the abstract Graphic3d_GraphicDriver interface. Also Aspect_, Quantity_, PrsMgr_, SelectMgr_, StdSelect_, V3d_.
TKOpenGl Low-level The only concrete Graphic3d_GraphicDriver implementation in OCCT. ~50k+ lines of GL/GLES code: shader compilation, texture binding, buffer management, render passes, picking buffers, ray tracing, PBR, shadows, transparency sorting.

We currently set BUILD_MODULE_Visualization=OFF and USE_OPENGL=OFF / USE_GLES2=OFF in Scripts/build-occt.sh, so the OCCTSwift xcframework ships none of these toolkits. OCCTSwift is a pure modeling kernel; visualization is OCCTSwiftViewport’s job.

The driver interface

Graphic3d_GraphicDriver is designed to be subclassed. The doc explicitly notes “potential for new Graphic3d_GraphicDriver implementations using other graphic APIs”. TKD3DHost is a precedent, but it isn’t a standalone driver, it’s a glue layer that wraps a TKOpenGl viewer in a Direct3D9 host surface. The cleanest historical example shows OCCT doesn’t ship a fully-parallel driver implementation; the abstraction surface has only ever had one concrete consumer.

What’s hardcoded to OpenGL

Quick spot check inside TKOpenGl: GLSL shaders for Phong + PBR + ray-tracing renderers, fixed-function pipeline state translation, framebuffer object management, multisample depth peeling for transparency, GPU pick buffer, environment cubemaps, shadow maps, FXAA. Every one of those would need a Metal-native equivalent in TKMetal.


OCCT roadmap signals

  • No Vulkan, no Metal in active development. As of OCCT 8.0.0-beta1 (May 2026):
    • Zero open PRs mentioning Vulkan in Open-Cascade-SAS/OCCT.
    • Zero issues mentioning Metal renderer.
    • No experimental branches.
  • OCCT maintainer Dmitrii Pasukhin on the forum (Future of OpenGL on Macs): “OCCT have plans to support Vulkan. It will be not so soon, but on long term plan we plan to support that renderer.”
  • The OCCT visualization page does say the 3D Viewer “might change considerably in the future with implementation of new features, improvements and adaptations to other graphic libraries like Vulkan”, but with no commitment to a date.
  • CADRays (sibling Open-Cascade-SAS project) provides a separate GPU ray tracer for OCCT models, it isn’t a Metal port either.

If you want OCCT-on-Metal, you build it. Don’t expect upstream.


Apple platform reality

Platform OpenGL status Native Metal Vulkan via MoltenVK
macOS 26 Deprecated since 10.14 (2018), still works via Apple’s GL-on-Metal compat shim Yes Yes (production-quality)
iOS 26 GLES deprecated since iOS 12, still works via compat Yes Yes
visionOS Not natively supported. OpenGL ES exists only as the WebGL2 base in Safari. App-level GL apps don’t run. Yes (only path) MoltenVK 1.3 added visionOS in 2025 (preview-class)
tvOS Same as iOS Yes Yes

visionOS is the forcing function for any move beyond OpenGL. OCCT’s TKOpenGl currently won’t run there at all without a translation layer, and Apple has been clear they won’t add native GL for new platforms.

We currently ship xros-arm64 and xros-arm64-simulator slices in OCCT.xcframework (v0.167.0), but those slices contain only the modeling kernel because we built with BUILD_MODULE_Visualization=OFF. If we wanted AIS_InteractiveContext on visionOS, today we have nothing.


Path A. Full TKMetal driver

Approach: subclass Graphic3d_GraphicDriver, mirror the TKOpenGl public surface in Metal terms.

Scope of work

  • Shader translation: every GLSL shader in TKOpenGl becomes MSL. Phong, PBR (metal-roughness), shadow map, post-process, ray-tracing kernels, picking. Either a manual rewrite or an automated path via spirv-cross / Naga.
  • Resource model: GL buffers/textures → Metal MTLBuffer/MTLTexture with discrete heap management.
  • Render passes: GL framebuffers → Metal MTLRenderPassDescriptor.
  • Command encoding: Metal’s modern explicit-encoder model has no GL equivalent, large architectural rewrite of the inner render loop.
  • Picking: GPU-side ID buffer with Metal imageblock memory (Apple TBDR-friendly).
  • Selection BVH: re-use SelectMgr_/StdSelect_ from TKService unchanged.
  • Transparency: depth-peeling implementation in Metal.
  • Ray tracing: optional. MetalRT exists for hardware ray tracing; mapping from OCCT’s OpenGl_View::raytrace is non-trivial.
  • Environment maps, FXAA, anisotropic textures, line stipple emulation: lots of small features each requiring a Metal port.

Effort estimate

Realistic range: 6–18 person-months for a usable subset, multi-year for production parity with current TKOpenGl. Comparable porting efforts:

  • VTK WebGPU backend (Kitware, 2024–): ongoing multi-year project, year 1 covered only polydata mappers; composite, glyph, volume, surface-LIC mappers still TBD.
  • Skia Metal backend: Google has a dedicated team, took years to reach parity with the GL backend.
  • Filament: ~2-year effort to ship Metal alongside GL/Vulkan, and Filament is a much smaller surface than OCCT’s viz layer.

Maintenance burden

OCCT releases land roughly twice yearly (8.0.0 in May 2026 after 7.9.x). Each release touches TKOpenGl. A downstream TKMetal would need to track those changes, an ongoing tax, not a one-shot.

Pros / cons

Pros

  • Full AIS surface preserved on Apple platforms including visionOS.
  • Same OCCT app code runs cross-platform with platform-specific drivers.
  • Upstream-friendly, could potentially be contributed back.

Cons

  • Largest possible scope.
  • Highest technical risk (Metal/GL architectural mismatch around resource state, command encoding).
  • Locked into OCCT’s release cadence for backports.

Path B. Mesh-extraction + native Metal (current)

Approach: OCCTSwift extracts triangulation (Mesh, Triangulation, Polygon3D) from B-Rep shapes; OCCTSwiftViewport renders those meshes natively in Metal.

What OCCTSwiftViewport already provides

From the README of gsdali/OCCTSwiftViewport:

  • Metal renderer with Blinn-Phong shading, 3-light setup, shadow maps, environment mapping
  • Camera systems: arcball / turntable / first-person, with inertia and animation
  • ViewCube: 26-region clickable orientation widget
  • GPU picking via TBDR imageblock-based pick ID buffer (body and face selection)
  • Display modes: wireframe, shaded, shaded-with-edges
  • Lighting presets: .threePoint, .studio, .architectural, .flat
  • Gesture presets: .default, .blender, .fusion360
  • Section / clip planes
  • Distance, angle, radius measurement overlays
  • Adaptive instanced dot grid + RGB axis lines
  • Swift 6 Sendable conformance, @MainActor isolation
  • iOS 18+ / macOS 15+

What it doesn’t do

  • No AIS_InteractiveContext-equivalent: app code holds the (Shape, ViewportBody) mapping itself. When Metal picking returns a face ID, the app has to look up which TopoDS_Face of which Shape that came from.
  • No standard OCCT widgets: AIS_Trihedron, AIS_Manipulator, AIS_Plane, AIS_Axis, AIS_PointCloud, dimension-annotation primitives, none of these exist as ready-made objects.
  • No ray-tracing renderer: TKOpenGl has one; OCCTSwiftViewport currently rasterizes only.
  • No PBR material editor surface (Blinn-Phong + light presets only).
  • No visionOS slice yet: OCCTSwiftViewport currently builds for macOS 15 / iOS 18.

Pros / cons

Pros

  • Already shipped, working, low maintenance.
  • Native Metal, clean visionOS path once the slice is added.
  • No coupling to OCCT release cadence.
  • Renders only what the app cares about; pure Apple stack.

Cons

  • App code carries the topology-to-pick-id mapping.
  • Standard CAD widgets (manipulators, dimensions, trihedrons) don’t exist; each is an app-level project.

Approach: keep OCCT visualization OFF in the xcframework. Build the high-value parts of AIS_InteractiveContext as a Swift layer on top of OCCTSwiftViewport’s Metal renderer.

What you’d build

A new product (call it OCCTSwiftAIS, sitting alongside OCCTSwiftTools):

Your App
  ├── OCCTSwift              (geometry kernel)
  ├── OCCTSwiftViewport      (Metal rendering, no OCCT)
  ├── OCCTSwiftTools         (Shape ↔ ViewportBody bridge)
  └── OCCTSwiftAIS           (NEW, AIS-equivalent layer)
        ├── InteractiveContext (selection / hover / highlight, topology-aware)
        ├── ManipulatorWidget  (translate / rotate gizmos in Metal)
        ├── DimensionAnnotation (linear / angular / radial overlays)
        ├── PresentationStyle  (highlighted, hover, dimmed, ghosted)
        └── Trihedron / Plane / Axis / PointCloud standard objects

Each of these is pure Swift logic over already-extracted topology metadata + Metal rendering primitives provided by OCCTSwiftViewport. The hard parts (vertex pipeline, lighting, shadow mapping, GPU picking) are already done; OCCTSwiftAIS adds the “this pick result is topoFace[7] of shape[3], highlight it” semantics.

Effort estimate

1–3 person-months for the headline features:

  • InteractiveContext and selection-from-topology: 2–3 weeks
  • Manipulator widget (translate/rotate, with snap): 2–3 weeks
  • Dimension annotations (linear, angular, radial; placement, leader lines, labels): 3–4 weeks
  • Standard objects (trihedron, plane, axis, point cloud): 1–2 weeks total
  • Hover/highlight/ghost styling: 1 week
  • Polish, docs, examples: 2 weeks

Pros / cons

Pros

  • Keeps the existing clean architecture (OCCTSwift = kernel, OCCTSwiftViewport = renderer).
  • Native Metal everywhere, including visionOS once OCCTSwiftViewport adds the slice.
  • Decoupled from OCCT release cadence, when OCCT 8.1 lands we don’t have to re-port a Metal driver.
  • Each feature is independently shippable; you can prioritise (selection first, manipulator second, dimensions third).

Cons

  • Not source-compatible with AIS_InteractiveContext-using OCCT C++ apps. OK for our stack, we’re Swift-first.
  • Doesn’t get OCCT’s ray-tracing renderer for free. (Probably not needed for interactive CAD anyway.)
  • Some duplication: the selection BVH logic in SelectMgr_/StdSelect_ would have to be re-implemented in Swift on top of the topology metadata we already extract.

Other paths considered and rejected

Path D. MoltenVK + OCCT-Vulkan

Build an OCCT Vulkan backend, run on Apple via MoltenVK.

  • Blocker: OCCT doesn’t have a Vulkan backend. If we wrote one, we’d be doing Path A’s effort for Vulkan instead of Metal, same scope, more dependencies.
  • MoltenVK on visionOS is preview-class as of late 2025; production risk is high.
  • Skip.

Path E. ANGLE-Metal

Route TKOpenGl’s GLES calls through Google’s ANGLE Metal backend.

  • ANGLE Metal backend exists and is active (Apple/Google collaboration upstreaming WebKit’s branch). MetalANGLE (the standalone fork) is unmaintained as of 2023.
  • ANGLE supports GLES 3.0 mostly; 3.1+ not fully. TKOpenGl uses GLES 3.0+ features.
  • No documented visionOS support for either ANGLE or MetalANGLE.
  • Performance penalty from translation layer.
  • Skip unless OCCT picks this up officially, and they haven’t.

Path F. WebGPU (Dawn / wgpu)

Use WebGPU as the cross-platform abstraction (it sits over Metal, Vulkan, D3D12).

  • VTK is doing this, multi-year effort. Apple Safari supports WebGPU.
  • Same scope as Path A, replace TKOpenGl entirely with TKWebGPU.
  • Doesn’t avoid the work; just changes which abstraction we target.
  • Interesting if we ever needed WebAssembly support; out of scope for an Apple-only Metal goal.
  • Skip for now.

Recommendation

Question Answer
Should we port TKOpenGl to TKMetal? No. Multi-year, high-risk, mostly duplicates OCCTSwiftViewport.
Should we ship visionOS visualization support? Yes, via OCCTSwiftViewport. Add the visionOS slice to that repo.
What’s missing from our current stack vs. OCCT’s AIS_InteractiveContext? High-level scene objects, selection-from-topology mapping, manipulator widgets, dimension annotations.
What’s the cheapest way to fill that gap? Path C, OCCTSwiftAIS as a Swift layer on top of OCCTSwiftViewport. ~1–3 person-months.

Concrete next step (when ready)

When the user wants to start the AIS layer:

  1. Create OCCTSwiftAIS repo (or a new product inside OCCTSwiftViewport, adjacent to OCCTSwiftTools).
  2. Start with selection-from-topology: an InteractiveContext Swift API that takes a Shape + extracted ViewportBody and exposes pickFace(at: CGPoint) -> TopoDS_Face?-style queries via OCCTSwiftViewport’s existing GPU picking buffer. This is the single highest-value missing piece.
  3. Add manipulator widget next, biggest visible win for user-facing CAD apps.
  4. Defer dimension annotations and standard-object widgets until there’s a concrete consumer (e.g. Unfolder or templotUX) asking for them.

This path keeps our architecture clean, keeps OCCTSwift’s xcframework at modeling-kernel-only (no GL dependency anywhere), and gives us full Apple platform reach including visionOS without a multi-year TKMetal project.


Sources