Skip to content

Releases: SecondMouseAU/OCCTSwiftViewport

v1.1.22 — NormalSmoothing striations fix (#81)

21 Jun 20:11

Choose a tag to compare

NormalSmoothing "brushed" striations fix (closes #81)

Fixes the fine periodic "brushed" striations that appeared on highly anisotropic CAD meshes — most visibly on threadedShaft helical flanks. This is the root cause of OCCTSwift#255 (it's a viewport shading bug, not an OCCT geometry bug).

NormalSmoothing.smoothNormals was discarding the per-vertex normals it was handed and recomputing each from an area-weighted face-normal average. On long thin triangles running along a sweep that average is directionally biased and renders as a sandpaper-like ripple.

Fix

Assign the area-weighted average of the original per-vertex normals within each crease group (snapshotted before the in-place write). Face normals are still used for crease detection, so hard edges stay crisp.

  • Smooth B-rep meshes → OCCT's analytic normals are reproduced (verified byte-identical to a raw-normal render of an M10×1.5 thread, 728K triangles) → striations gone.
  • Flat STL (vertex normal == face normal) → reduces to the old face-normal average → backward-compatible.

Tests

New smoothInputNormalsPreserved (the #81 regression) + flatInputMatchesFaceNormalAverage (backward-compat); updated the crease test to seed realistic per-face normals. 163 tests pass.

Full Changelog: v1.1.21...v1.1.22

v1.1.21 — Unlit display mode (#77)

19 Jun 20:00

Choose a tag to compare

Unlit / flat-colour display mode (closes #77)

New DisplayMode.unlit draws each body in its constant base colour with no lighting, ambient, shadows, fresnel, curvature, or tone mapping — so vivid, colour-coded diagnostic / debug renders stay faithful and distinguishable.

Previously OffscreenRenderer .shaded ran every body through the full PBR path (hemisphere ambient + fresnel rim + curvature; ACES tone map on the interactive post-pass), which desaturated and hue-shifted saturated colours — a bright magenta read as green-ish, breaking region colour-coding (e.g. OCCTReconstruct's diagnostic renders).

How it works

  • shaded_fragment early-returns bodyUniforms.color when the new Uniforms.unlit flag is set (clip-plane discard + selection tint still apply).
  • Both OffscreenRenderer and ViewportRenderer set the flag from their displayMode; .unlit routes through the shaded pipeline via showsSurfaces == true. The interactive SSAO / ACES tone-map post-pass is skipped for .unlit.
  • Uniforms gains a uint unlit field (Swift↔Metal in sync; repacked the existing clip-pad tail, stride unchanged).

Verification

New UnlitColorTests: a magenta panel renders faithfully in .unlit (R≈255, G≈38, B≈217) and measurably more saturated than .shaded. 161 tests pass.

Full Changelog: v1.1.20...v1.1.21

v1.1.20 — Tap-to-measure (#68)

12 Jun 10:11
069d894

Choose a tag to compare

Tap-to-measure (issue #68)

ViewportController.measurementMode (.distance / .angle / .radius) now actually drives interaction. While a mode is active, taps on geometry accumulate world-space surface points and commit a ViewportMeasurement (rendered by the existing MeasurementOverlay). Previously the property was published but consumed by nothing.

Added

  • Point order per mode: .distance → start, end (2 taps); .angle → armA, vertex, armB (3 taps); .radius → center, edge (2 taps).
  • ViewportBody.worldHitPoint(ray:triangleIndex:) — reconstructs the picked surface point in world space, respecting the body's transform.
  • Controller: pendingMeasurementPoints, addMeasurementPoint(_:), handleMeasurementPick(...), cancelPendingMeasurement(), clearMeasurements(), static pointCount(for:). Mode change clears pending; face picks only; selection stream untouched.
  • MeasurementMode is now Equatable.

Tests

  • New MeasurementModeTests (14). 160 tests total, all green.

Additive and source-compatible.

🤖 Generated with Claude Code

v1.1.16 — Cube drag direction fix

08 Jun 12:42
4c7e900

Choose a tag to compare

Follow-up to v1.1.15: dragging the navigation cube now orbits the camera the intended way (the cube is a camera proxy, so it orbits around the model — opposite sign to the viewport's grab-the-model drag). 142 tests.

v1.1.15 — Cube drag-to-orbit + edge/corner targets

08 Jun 03:12
4ab0f90

Choose a tag to compare

Follow-up to #60: the navigation cube is now drag-to-orbit (grab-and-spin); a non-moving press still snaps to the tapped face/edge/corner. Faces draw a 3x3 grid so edge/corner zones are discoverable, and the cube is larger (96pt) so they're reachable. Classifier round-trip verified under the iso rotation. 142 tests. Lives here (shared viewport widget) for ecosystem commonality.

v1.1.14 — Non-pickable bodies

08 Jun 02:17
6be6602

Choose a tag to compare

Closes #63: ViewportBody.isPickable (default true) excludes a body from the GPU pick buffer while still drawing it, so always-on-top reference/overlay bodies (datum/ground planes) stop stealing face/edge/vertex picks. Gated in every pick sub-pass; pick IDs stay stable. PickabilityTests; 141 tests; no behaviour change by default.

v1.1.13 — View cube position

08 Jun 02:12
67c5f1e

Choose a tag to compare

Closes #62: the view-cube overlay now honours ViewportConfiguration.viewCubePosition (topLeading/topTrailing/bottomLeading/bottomTrailing) instead of being hardcoded bottom-trailing — so hosts can move it clear of e.g. an iPhone bottom sheet. Default unchanged. 138 tests.

v1.1.12 — Interactive navigation cube

08 Jun 01:02
6dc1517

Choose a tag to compare

Closes #60: NavigationCubeView — a Shapr3D/Fusion-style cube tracking the camera with clickable faces/edges/corners that snap to plan/elevation/iso views (goToRegion). Pure unit-tested NavigationCube hit-test (ray→cube→3x3-per-face → 26 regions); robust iOS+macOS. NavigationCubeTests; 136 tests; rendering verified on Vision Pro sim.

v1.1.11 — Scene-adaptive clip planes (z-fighting fix)

05 Jun 22:34
3c60215

Choose a tag to compare

Closes #57: near/far clip planes are now derived per frame from camera distance + scene radius (CameraState.clipPlanes), keeping far/near ~1e3 at any model scale instead of the fixed 0.01/10000 (1e6) range that caused z-fighting on large/real-scale models. Both renderers. ClipPlaneTests; 131 tests; verified on Vision Pro sim. No API change.

v1.1.10 — Headless per-body transforms

05 Jun 22:14
a632181

Choose a tag to compare

Closes #55: OffscreenRenderer now applies body.transform (shaded/transparent/point/shadow passes + transformed shadow-frustum bounds), so transformed/instanced/assembled bodies render correctly headlessly. Matches ViewportRenderer. OffscreenTransformTests; 126 tests.