Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
175 commits
Select commit Hold shift + click to select a range
cec3d91
Add Category enum + per-category mute mask to UvtLog
claude Apr 18, 2026
43bcbb1
Add BenchmarkRecorder + SymSplit/Topology metric hooks
claude Apr 18, 2026
0e6c72a
Wire BenchmarkRecorder into LightmapTransferTool pipeline entry points
claude Apr 18, 2026
f71eeb0
Add Validation Overlay filter + Log filters UI
claude Apr 18, 2026
f14344a
Add TestSuiteAsset + TRANSFER_BENCHMARK docs
claude Apr 18, 2026
ef6ffaf
Add atlasRes/shellPad/borderPad sweep runner
claude Apr 18, 2026
3b80c83
Add FbxMetricsExporter: CSV + per-mesh UV0/UV2 PNG dumps
claude Apr 19, 2026
9736fd5
Auto-dump result UV2 PNG per mesh in BenchmarkRecorder
claude Apr 19, 2026
03f0bf8
Fix PR#105 review comments: per-target topology, sweep cancel, cache …
claude Apr 19, 2026
d17d60c
Benchmark results: LegacyFixed sweep on Playground, Wooden_Box_Long, …
SashaRX Apr 19, 2026
4cda91e
Analysis: LegacyFixed sweep results (2026-04-19)
claude Apr 19, 2026
b3674d9
Add UV2 sweep gallery index (test push)
SashaRX Apr 19, 2026
f2cfb47
Add per-model UV2 sweep galleries (Carousel/Gazebo/Playground/Wooden_…
claude Apr 19, 2026
17d93d3
Fix unreadable links in sweep gallery (dark-mode friendly color)
claude Apr 20, 2026
459f110
Add 'Skip SymSplit step' diagnostic toggle
claude Apr 20, 2026
d8be348
Merge remote-tracking branch 'origin/main' into claude/optimize-trans…
claude Apr 24, 2026
42613d4
Align new feature files with SashaRX.UnityMeshLab namespace
claude Apr 24, 2026
de1c575
Merge branch 'results/legacyfixed-2026-04-19' of https://github.com/S…
SashaRX Apr 24, 2026
5f11065
Update diagnostic toggle for SymSplit step in ExecFullPipelineCore
SashaRX Apr 24, 2026
f4216da
Drop _results from feature branch (data lives on results/ branch as _…
SashaRX Apr 24, 2026
3df9789
Merge remote-tracking branch 'origin/main' into claude/optimize-trans…
claude Apr 24, 2026
fe2688c
Add Tools/build_gallery.py with voting UI
claude Apr 25, 2026
a0ccd3e
Add Tools/gen.bat wrapper for gallery builder
claude Apr 27, 2026
ab36b06
Fix tiled-UV0 atlas underfill: NormalizeAtlasFill + atlasUtilization …
claude Apr 27, 2026
d30eca4
Replace Prefab Builder sidebar with new Hierarchy view (PR-1)
claude May 3, 2026
8d75cbe
Fix CS0266 on meshOptimizationFlags snapshot variable
claude May 3, 2026
79fc049
Move Mesh Lab window opener into submenu to avoid menu collapse
claude May 3, 2026
dff6422
Highlight pre-Apply state and emphasise Dummy block boundaries
claude May 3, 2026
8716eec
Make pre-Apply highlight visible via GUI.backgroundColor
claude May 3, 2026
5af0749
Tree indent, auto-renumber on Insert/Delete, clearer status markers
claude May 3, 2026
08432e8
Surface Collider components on Dummy/Root in Hierarchy COL rows
claude May 3, 2026
68ff843
Fix NRE on Rebuild Names + visible tree connector + preserve leaf base
claude May 3, 2026
73374df
Address Codex review on PR #111: non-destructive regen + last-LOD guard
claude May 3, 2026
7f1c5c3
Keep fresh-LOD highlight visible after Hub-driven OnRefresh
claude May 3, 2026
fc8ace1
Lock importTangents=CalculateMikk on FBX-overwrite imports (PR #107 f…
claude May 3, 2026
180c35b
Compact LODGroup, sibling-position new LOD, separate rows, scope NEW …
claude May 3, 2026
dc5962b
Deferred-insert / deferred-delete model + Apply Changes single commit
claude May 3, 2026
ff31e1e
Sync inserts across all dummies, fix UV badges, click-to-ping rows
claude May 3, 2026
1df32a8
PR-2A/2B: right Settings stack with LOD Gen migrated as first vertica…
claude May 3, 2026
6f6bd8d
Move Settings stack into a hub-level right sidebar
claude May 4, 2026
035673d
Clamp right sidebar to window width; trim LOD Settings to weights only
claude May 4, 2026
a447fdf
Address Codex review on PR #111: insert-after-delete + regen Discard
claude May 4, 2026
e76099f
Add TangentValidator to detect and enforce TBN data integrity (#112)
SashaRX May 4, 2026
f0957c5
Bump version to 1.0.3 [skip ci]
github-actions[bot] May 4, 2026
30c0d3d
Merge remote-tracking branch 'origin/main' into claude/prefab-builder…
claude May 4, 2026
28ba025
Right sidebar holds 180 px minimum and squeezes viewport instead
claude May 4, 2026
b15b27c
Group LOD rows by chain base name within each Dummy block
claude May 4, 2026
6ac59e9
Canvas takes explicit width so it shrinks first when window narrows
claude May 4, 2026
3000191
Unity Hierarchy-style chain foldouts with per-level indent
claude May 4, 2026
f54ed46
Per-mesh-group color palette shared between hierarchy and UV2 panel
claude May 4, 2026
023f149
Tint chain helpBox with the per-group palette colour
claude May 4, 2026
41e947a
Strip chain base from LOD / COL row labels
claude May 4, 2026
2711b7b
+ Add Dummy button, empty containers, polygon-derived slider default
claude May 4, 2026
5d1d33d
Compact LOD rows; small + insert button; Wrap chain in Dummy action
claude May 5, 2026
3065e86
Defer Wrap chain + Add Dummy until Apply Changes; auto-unpack prefab
claude May 5, 2026
9340174
+ insert padding, pending Dummy placeholder, full-width slider row
claude May 5, 2026
061ef95
Add explicit right padding inside chain helpBox rows
claude May 5, 2026
1e524e0
Center + insert button via FlexibleSpace to stop right-edge clipping
claude May 5, 2026
c099a12
Cleaner LOD row rhythm: drop inter-row +, align right column
claude May 5, 2026
f867c51
Compact LOD row: 2 lines, channel badges on chain header
claude May 5, 2026
21719c7
Inline value field with slider via fieldWidth instead of two widgets
claude May 5, 2026
9b04b96
Visible gap + divider between chain block and COL rows
claude May 5, 2026
dbcce5f
Wrap COL section in its own helpBox; add trailing pad on COL row
claude May 5, 2026
d194dea
Add Binary Hit toggle to vertex AO baker for sharper corner shading
claude May 8, 2026
9ba07e3
Merge pull request #113 from SashaRX/claude/compare-vertex-color-bake…
SashaRX May 8, 2026
ec3211b
Bump version to 1.0.4 [skip ci]
github-actions[bot] May 8, 2026
f5b2fd7
Add Embree integration plan document
claude May 9, 2026
6c5afd0
Merge pull request #114 from SashaRX/claude/add-embree-sdf-PwoX3
SashaRX May 9, 2026
ae1320e
Merge remote-tracking branch 'origin/main' into claude/optimize-trans…
claude May 9, 2026
79021fd
Pre-rotate thin UV0 shells (aspect > 3:1) before feeding xatlas
claude May 11, 2026
e789578
Group-aware xatlas repack: merge overlap-tile shells into single chart
claude May 11, 2026
e6b1090
Add Tests/Editor scaffolding + smoke tests
claude May 11, 2026
82acbd3
Add Tests.meta (root folder meta missed in previous commit)
claude May 11, 2026
99a55b4
Expose xatlas bruteForce / rotateCharts / mergeOverlappingTiles in GUI
claude May 11, 2026
bb81f19
Build native libraries (auto) [skip ci]
github-actions[bot] May 11, 2026
96d375f
Harden tile-merge equivalence with shape signature check
SashaRX May 11, 2026
6ce3ff2
Merge pull request #115 from SashaRX/codex/fix-high-priority-bugs-fro…
SashaRX May 11, 2026
4878af5
Address Codex PR #105 review (P1 #3 + P2 cluster)
claude May 11, 2026
3f33d62
Fix duplicate TestRunner references in Tests asmdef
claude May 11, 2026
3e07d1d
Fix HashSet indexing in tile-merge guard; hide Tools/ from Unity
claude May 11, 2026
6ae6b55
Pass full shells list to FixOverlappingUv2Shells
claude May 11, 2026
1381146
Instrument tile-dispatch loop to localize 'dispatched=0' bug
claude May 11, 2026
edbb6ec
Wipe ghost xatlas UV2 from dup-shell verts before dispatch
claude May 11, 2026
da6fe40
Accept tile-merge via UV0 AABB IoU when topology differs
claude May 11, 2026
e6cf458
Require 3D shape match before tile-merging via UV0 IoU
claude May 11, 2026
9674285
Disable tile-merge by default; run UV0 perturbation unconditionally
claude May 11, 2026
1d4be3a
Trust xatlas: stronger perturbation, skip AABB fix-passes
claude May 11, 2026
564b3d0
Expose tile-merge magic constants in RepackOptions
claude May 11, 2026
cd8fd1a
Add per-shell texel-density normalization (pre-pack)
claude May 12, 2026
5234d3f
Add meta for TexelDensityNormalizer.cs
claude May 12, 2026
f690562
Cap normalized UV total area + log atlas utilization
claude May 12, 2026
f708eda
Add using System; for Math.Abs in ComputeUv2CoverageFraction
claude May 12, 2026
cc90cab
Qualify Object.* calls in RepackUv after 'using System;' was added
claude May 12, 2026
c6cca97
Expose remaining xatlas pack options in UI
claude May 12, 2026
751051f
Add per-shell aspect-ratio normalization
claude May 12, 2026
19d514a
Update Max Shell Aspect Slider Range in LightmapTransferTool
SashaRX May 12, 2026
69160a8
Update Max Shell Aspect Slider Minimum in LightmapTransferTool
SashaRX May 12, 2026
f0cb32f
Rewrite shell aspect normalization on PCA, run before density
claude May 12, 2026
e4e80e6
Remove the 'merge overlap tiles' mode and its post-process fix passes
claude May 12, 2026
57a15d8
Address Codex P2 cluster on PR #105 (3 items)
claude May 12, 2026
41fc9ee
Document pipeline state and removed modes in TRANSFER_BENCHMARK
claude May 12, 2026
afc411f
Surface compression block size in Repack UI
claude May 12, 2026
77f6013
Add post-transfer collapse-to-line diagnostic
claude May 12, 2026
3704c78
Add hard-edge shell-split analyzer (logging only)
claude May 12, 2026
bd90f84
Address Codex review on 3704c78 (3 P1 + 2 P2)
claude May 12, 2026
09fe868
Replace PCA-of-positions aspect with Sander L² stretch metric
claude May 12, 2026
f4b13f1
Stop collapsing force3D fallback shells to centroid
claude May 12, 2026
ddfd174
Replace per-shell aspect with global unwrap-aspect normalize
claude May 12, 2026
6321cac
Add per-shell aspect normalization pass
claude May 12, 2026
cbee977
Expose per-shell aspect tuning to UI
claude May 12, 2026
77e07ca
Add ARAP re-parameterization for ribbon shells (opt-in)
claude May 12, 2026
4f3bf8a
Fix ARAP regressions on mirrored / trivial ribbon shells
claude May 12, 2026
1e8db1e
Replace PCA-based per-shell aspect with edge-unfold + Sander CV filter
claude May 12, 2026
dbdae63
Add benchmark sweep runner with auto best-config selection
claude May 12, 2026
6d5fd58
Clamp lightmap UV2 into [0,1] (opt-in, default on)
claude May 12, 2026
1e3a15d
ARAP: bump iteration default to 50, widen slider to [10,200]
claude May 12, 2026
436d60c
Unify sweep into TestSuiteAsset, drop hardcoded 12-run grid
claude May 12, 2026
958d6e2
Fix CS0117: use existing Category.Match for transfer-site clamp log
claude May 12, 2026
2ca8edb
Emit sortable HTML gallery from sweep aggregator
claude May 12, 2026
3a3989d
Survive mid-sweep Unity crashes with incremental aggregate + recovery
claude May 12, 2026
30e2032
UI: stack sweep ObjectField above buttons, drop fixed widths
claude May 12, 2026
147028d
Drop Sander CV skip-gate from per-shell aspect — it suppressed everyt…
claude May 12, 2026
6e1c16a
Architectural fix: replace per-shell aspect with Sander L² + auto-ARAP
claude May 12, 2026
ebb0ad3
Run ARAP BEFORE TexelDensityNormalizer (correct pipeline order)
claude May 12, 2026
660f54b
Pipeline order: Global aspect → ARAP → Density; sweep gains aspect axis
claude May 12, 2026
8b58de1
Fix L² stretch formula — scale-invariant condition metric
claude May 12, 2026
2ec4ab1
Fix CS0103: add 'using System;' for System.Math in ShellQuality.cs
claude May 12, 2026
8a0d806
Fix perturbation collapsing symmetric fan shells into slivers
claude May 12, 2026
d5393c5
Remove global aspect normalize — architecturally wrong layer
claude May 12, 2026
21a54da
Address Codex review on PR #105
claude May 12, 2026
feeff68
Add density distribution diagnostic to TexelDensityNormalizer
claude May 12, 2026
4f54989
Add post-xatlas UV2 density diagnostic
claude May 12, 2026
6865650
Force xatlas to honour per-shell density via explicit texelsPerUnit
claude May 12, 2026
5137622
Raise default UV coverage budget to 0.95
claude May 12, 2026
8ecc27b
Add Auto-from-texel-density resolution mode to Repack
claude May 12, 2026
dc399a2
Revert texelsPerUnit=resolution fix — broke xatlas packing
claude May 12, 2026
cac2ebd
Add density checkpoints at each post-xatlas stage
claude May 12, 2026
adde4bd
Add post-pack density correction (shrink-only)
claude May 12, 2026
25ed2ab
Oversample internal xatlas atlas to neutralise ceil(extents) bias
claude May 12, 2026
ee000cd
Tame oversample × brute-force runaway
claude May 12, 2026
46170ba
Make xatlas pack cancellable + cost-budget preflight
claude May 12, 2026
f3a3e8b
Switch density fix to post-pack correction by default
claude May 12, 2026
6c81e6c
Fork xatlas + PreserveChartScale option for uniform lightmap density
claude May 12, 2026
a2b95a1
Build native libraries (auto) [skip ci]
github-actions[bot] May 12, 2026
ec5dd12
Add bridge build marker printf to diagnose stale DLL
claude May 12, 2026
883355c
Add cstdio include for printf/fflush in bridge debug marker
claude May 12, 2026
e1b319e
Build native libraries (auto) [skip ci]
github-actions[bot] May 12, 2026
842c897
Bump to 1.0.5 — xatlas fork PreserveChartScale + auto-resolution + de…
claude May 12, 2026
4c3e3f2
Replace native printf marker with managed probe function
claude May 12, 2026
490f4c9
Build native libraries (auto) [skip ci]
github-actions[bot] May 12, 2026
9226f7f
Add Stage B runtime diagnostic counters
claude May 13, 2026
a44c73a
Build native libraries (auto) [skip ci]
github-actions[bot] May 13, 2026
716f8bd
Replace xatlas fork with pre-pack integer-pixel snap + Codex fixes
claude May 13, 2026
3bb431b
Build native libraries (auto) [skip ci]
github-actions[bot] May 13, 2026
5544242
Pass explicit texelsPerUnit to xatlas so snap grid matches pack grid
claude May 13, 2026
b3be1f5
Force rotateCharts=0 when snap is on (rotation invalidates snap grid)
claude May 13, 2026
cd0b0b0
Snap to xatlas's actual chart-scale grid, not raw tpu
claude May 13, 2026
2f0b143
Revert wrong sqrt(s/p) factor, disable xatlas maxChartSize clamp on snap
claude May 13, 2026
9c03555
Move snap after perturb (perturb was undoing the snap)
claude May 13, 2026
a6541a4
Revert pre-pack snap experiment — does not work, made worse
claude May 13, 2026
6dcedea
Bump pack defaults + add Stage B amplification diagnostic
claude May 13, 2026
a218a2b
Drop Perturb (xatlas does not dedup UvMesh) + actually apply oversamp…
claude May 13, 2026
d4b5d3c
Document density-spread fix (14x -> 1.17x) + known regressions
claude May 13, 2026
f98da96
Address 5 Codex review comments on benchmark sweep + FBX metrics
claude May 13, 2026
3f71305
Merge pull request #105 from SashaRX/claude/optimize-transfer-modes-f…
SashaRX May 13, 2026
e1712ae
Bump version to 1.0.6 [skip ci]
github-actions[bot] May 13, 2026
b2efafe
Build native libraries (auto) [skip ci]
github-actions[bot] May 13, 2026
89c3f67
Fix oversample repack and transfer regressions
SashaRX May 13, 2026
b225b38
Clarify brute force availability in repack UI
SashaRX May 13, 2026
b480ef6
Enhance transfer pipeline by skipping transfer/auto-tune when no targ…
SashaRX May 13, 2026
1b738a9
Clean up transfer target test meshes
SashaRX May 13, 2026
c2723c8
Merge pull request #116 from SashaRX/codex/fix-oversample-transfer-re…
SashaRX May 13, 2026
2f5d53c
Bump version to 1.0.7 [skip ci]
github-actions[bot] May 13, 2026
2b55a6c
Merge remote-tracking branch 'origin/main' into claude/prefab-builder…
claude May 13, 2026
a63411a
Build native libraries (auto) [skip ci]
github-actions[bot] May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"cmake.ignoreCMakeListsMissing": true
}
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
### Refactored
- `LightmapTransferTool.ExportVertexColorsToFbxCore` now accepts an optional `outputFbxPathOverride` and returns `bool` for success. When the override is set and differs from the source path, Phase 1 (source importer mutation), Phase 4 scene relink, and Phase 5 restore are skipped so the source FBX and live scene stay untouched. Existing overwrite and hierarchy-mode callers keep their void-style usage.

## [1.0.5] - 2026-05-13

### Added
- **Pre-pack shell snap to integer atlas pixels** (`SnapShellsToIntegerPixels`, default ON). Before handing shells to xatlas, each shell is scaled per-axis around its UV centroid so its bbox extent is an integer number of atlas texels. Makes xatlas's own per-chart `ceil(extents)` rescale (xatlas.cpp ~line 8345, upstream Issue #18 wontfix) a no-op for every chart, so the uniform per-shell density set up by `TexelDensityNormalizer` survives the pack instead of being amplified by sub-pixel rounding. **No xatlas fork required** — the package builds stock xatlas master via `FetchContent`.
- Auto-resolution mode for Repack (`ResolutionMode.AutoFromTexelDensity`) — pick a target texels-per-meter density and the tool computes the atlas resolution from total 3D area. Manual mode unchanged. Sweep automatically forces Manual so each cell's `atlasResolutions[i]` is the resolution xatlas actually packs at.
- `[Density]` / `[Density:snap]` / `[Density:postUV2]` diagnostic logs at multiple pipeline checkpoints (snap / postAssign / postOrphan / postBorder / postCorrection / final) so per-shell density drift is visible per stage.
- Cancellable xatlas pack — `xatlasPackCharts` now runs on a background `Task` while the main thread polls `DisplayCancelableProgressBar`. xatlas itself has no native cancel API, so cancel = wait for in-flight pack to finish, then discard result and stop pipeline.
- Pack cost-budget preflight — refuses packs that would take many minutes (brute-force budget 500M ops, heuristic 20B). Auto-disables brute force above the budget instead of hanging the editor.
- UI toggles in Pre-pack panel: `Snap shells to integer atlas pixels (pre-pack)`, `Post-pack density correction (experimental)`, `Internal pack oversample` popup.

### Fixed
- Per-shell lightmap texel density variance on real artist UVs (target ~1× from ~14× spread). Achieved purely via input preparation — no xatlas patch required.
- Sweep `atlasResolutions` dimension was collapsed to a single value when `RepackResolutionMode == AutoFromTexelDensity` (every cell recomputed and overrode the swept value). Sweep now snapshots and forces Manual for the duration.
- `BenchmarkRecorder` `atlasRes` column now reflects the resolution xatlas actually packed at (post auto-compute), not the raw `ctx.AtlasResolution` UI setting.
- Benchmark per-mesh records now skip entries with `include == false` so user-deselected meshes carrying stale `TransferResult` / `ValidationReport` don't surface as failed rows in sweep aggregates.
- `BenchmarkSweep` `totalMs` no longer double-counts inner stages — `pipelineMs` is the outermost wall clock and already contains repack + transfer + validate; summing all four triple-counted inner work. Standalone Repack/Transfer rows (no pipeline wrapper) fall back to the sum of inner stages.

### Changed
- `TexelDensityNormalizer` now logs a rich `[Density] pre … post … scale …` summary at Info level instead of a terse "rescaled N/N shells" line.
- `Native~/third_party/xatlas/` removed; `Native~/CMakeLists.txt` reverted to `FetchContent_Declare(xatlas)` against upstream master.

## [1.0.0] - 2026-04-20

### Changed (breaking)
Expand Down
270 changes: 270 additions & 0 deletions Documentation~/EMBREE_INTEGRATION_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# Embree Integration Plan

Plan for adding [Intel Embree 4](https://github.com/RenderKit/embree) as an
optional native acceleration backend for transfer, AO baking, and future SDF
generation. Branch: `claude/add-embree-sdf-PwoX3`.

## Why

Three existing pipelines need fast spatial queries on triangle meshes:

1. **Transfer** (`TransferData.cs`, `GroupedShellTransfer.cs`) — closest-point
from LOD_N vertices onto LOD_0 surface, plus barycentric interpolation of
UV2 / vertex attributes. Currently uses managed `TriangleBvh.cs` (512 LoC).
2. **Vertex AO** (`VertexAOBaker.Cpu.cs`, `.Gpu.cs`) — hemisphere ray casts per
vertex against scene geometry. CPU path is single-threaded managed BVH;
GPU path is a DX11/Vulkan ComputeShader.
3. **SDF generation** (planned) — signed-distance field grids for
collision/voxelization workflows.

All three are textbook Embree use-cases. Embree gives 3–10× over managed BVH
for AO (SIMD ray packets + mature SAH BVH) and removes the GPU dependency for
users without a capable Compute backend.

## Scope

- **Optional** native backend, gated by `UNITYMESHLAB_EMBREE` scripting define.
- Without the binary, the package builds and runs exactly as today
(managed `TriangleBvh` + `VertexAOBaker.Cpu`/`.Gpu` fallbacks).
- **Platforms (initial):** Windows x64, Linux x64.
- **Platforms (deferred):** macOS (Apple Silicon arm64). No dev hardware
available — fallback to managed BVH + existing Metal-transpiled GPU AO.

## Non-goals

- Replacing the managed `TriangleBvh` outright. It stays as the default
fallback and the source of truth for behaviour.
- Wrapping every Embree feature. We expose only point-query, occlusion-rays,
and SDF-grid entry points.
- Building Embree from source inside Unity. Native lib is built separately
via `Native~/Embree/build_embree.{bat,sh}` and the result lives in
`Plugins/x86_64/`.

## Architecture

### Native artifact

Separate shared library **`umlab-embree`**, NOT merged with the existing
`xatlas-unity` plugin. Embree + TBB add ~30–50 MB and many users won't
need the Embree backend.

```
Plugins/x86_64/
xatlas-unity.dll (existing)
xatlas-unity.so (existing)
umlab-embree.dll (new)
umlab-embree.so (new)
tbb12.dll (new, runtime dep of Embree)
libtbb.so.12 (new)
```

### Source layout

```
Native~/
CMakeLists.txt (existing, untouched — xatlas-unity)
xatlas-unity-bridge.cpp (existing)
src/collision.cpp (existing)
third_party/ (existing — VHACD)
Embree/ (NEW)
CMakeLists.txt FetchContent embree v4.3+, statically link
where possible, copy DLL/so to Plugins/x86_64/
umlab-embree.h C ABI header
umlab-embree.cpp C ABI implementation
build_embree.bat Win64 release build helper
build_embree.sh Linux x64 release build helper
third_party/
LICENSE-EMBREE.txt Apache 2.0 attribution
LICENSE-TBB.txt Apache 2.0 attribution
```

### C# layout

```
Editor/
Native/ (NEW folder — colocated P/Invoke wrappers)
EmbreeNative.cs [DllImport("umlab-embree")] declarations
EmbreeScene.cs IDisposable handle wrapper, cache by mesh id
IBvhBackend.cs Common interface (closest-point, raycast)
TriangleBvh.cs (existing) → implements IBvhBackend
EmbreeBvh.cs (NEW) → implements IBvhBackend
BvhBackendFactory.cs (NEW) Selects Embree if available, else managed
VertexAOBaker.cs (existing) Add Backend.Embree enum value
VertexAOBaker.Embree.cs (NEW) Sibling of .Cpu / .Gpu
```

### Define management

Extend `Editor/PostprocessorDefineManager.cs`:

- On editor load, check for presence of `Plugins/x86_64/umlab-embree.dll` (Win)
or `Plugins/x86_64/umlab-embree.so` (Linux).
- If present: add `UNITYMESHLAB_EMBREE` to `PlayerSettings` scripting defines
(Editor platform group). If absent: remove it.
- Mirrors the existing pattern for `LIGHTMAP_UV_TOOL_FBX_EXPORTER`.

## C ABI surface

Minimal, batched, handle-based. Single P/Invoke per thousands of points to
avoid marshalling overhead.

```c
// ── Scene lifecycle ──
typedef struct EmbreeSceneOpaque* uml_embree_scene_t;

uml_embree_scene_t uml_embree_scene_create(void);
void uml_embree_scene_destroy(uml_embree_scene_t);

// Returns geom_id (>=0) on success, -1 on failure.
int uml_embree_scene_add_mesh(
uml_embree_scene_t scene,
const float* vertices, int vertex_count, // xyz, tightly packed
const int* triangles, int tri_count); // i0,i1,i2 per tri

void uml_embree_scene_commit(uml_embree_scene_t); // builds BVH

// ── Transfer: closest-point batch ──
// For each query point, finds closest point on any committed mesh.
void uml_embree_closest_points(
uml_embree_scene_t scene,
const float* points, int point_count, // input: xyz per point
float* out_positions, // xyz, hit position
float* out_normals, // xyz, surface normal
int* out_geom_ids, // -1 if no hit
int* out_prim_ids,
float* out_barycentrics); // u, v per hit (w = 1-u-v)

// ── AO bake batch ──
// Cosine-weighted hemisphere sampling, occlusion test against the scene.
// Returns ao in [0,1] where 1 = fully unoccluded.
void uml_embree_ao_bake(
uml_embree_scene_t scene,
const float* points, const float* normals, int point_count,
int samples_per_point,
float max_distance,
unsigned int rng_seed,
float* out_ao);

// ── SDF grid (deferred to PR6) ──
void uml_embree_sdf_grid(
uml_embree_scene_t scene,
const float* origin, const float* cell_size,
int nx, int ny, int nz,
float* out_sdf); // signed distance per cell
```

All functions are thread-safe to call sequentially; Embree itself parallelizes
the batch internally via TBB. Do NOT wrap calls in Unity Job System — would
cause TBB/Job pool contention.

## Integration points

| File | Change |
|---------------------------------|-----------------------------------------------------------------------------------------------------------------|
| `TriangleBvh.cs` | Extract `IBvhBackend` interface (closest-point + raycast). Existing class implements it. No behaviour change. |
| `TransferData.cs` | Take `IBvhBackend` from factory instead of `new TriangleBvh(...)` directly. |
| `GroupedShellTransfer.cs` | Same pattern. |
| `CoverageSplitSolver.cs` | Same pattern. |
| `VertexAOBaker.cs` | Add `Backend.Embree` to enum. Auto-select if `UNITYMESHLAB_EMBREE` and CPU path requested and scene non-empty. |
| `VertexAOBaker.Embree.cs` | New file: builds Embree scene from input mesh + occluders, calls `uml_embree_ao_bake`, fills vertex AO array. |
| `PostprocessorDefineManager.cs` | Add Embree binary detection alongside existing FBX exporter detection. |

`UvTransferPipeline.cs` — no changes, already abstracted through `TransferData`.

## Performance & caching

- **BVH build cost**: 50–500 ms for typical game meshes. Cache per
`(Mesh.GetInstanceID(), Mesh.vertexCount, Mesh.triangles.Length)` tuple in
`EmbreeScene` static dictionary. Drop on `AssemblyReloadEvents`.
- **Threading**: Embree handles parallelism. C# side issues one P/Invoke per
batch of N points; do NOT slice into Jobs.
- **Memory**: `rtcReleaseScene` on dispose. EditorWindow `OnDisable` must
flush the cache for any scenes it owns.

## Risks & gotchas

- **TBB runtime dependency**: Embree links TBB dynamically by default.
Either statically link TBB inside `umlab-embree.dll` (preferred, single
artifact) or ship `tbb12.dll` / `libtbb.so.12` next to it. CMake decision
in PR1.
- **CRT mismatch (Windows)**: Embree precompiled binaries use MSVC dynamic
CRT. Build `umlab-embree.dll` with the same CRT, otherwise heap-cross-DLL
crashes. Pin to `/MD` in CMake.
- **glibc baseline (Linux)**: Build on Ubuntu 20.04 image to keep glibc 2.31
compatibility. Newer images produce binaries that fail on older Steam
Runtime / CentOS targets.
- **macOS not supported**: `Native~/Embree/CMakeLists.txt` will
`message(FATAL_ERROR)` on `APPLE` to prevent accidental broken builds.
Mac users get the managed fallback automatically (define is not set).
- **License**: Embree (Apache 2.0) and TBB (Apache 2.0) both require
attribution. Add `LICENSE-EMBREE.txt` and `LICENSE-TBB.txt` to
`Native~/Embree/third_party/`. Mention in `CHANGELOG.md` on first release.
- **Plugin import settings**: `umlab-embree.dll` and `umlab-embree.so` need
`.meta` files marking them as Editor-only x86_64. Pattern matches the
existing `xatlas-unity` `.meta` files.

## Rollout (small PRs)

### PR1 — Native skeleton + CI
- Add `Native~/Embree/` with CMake, empty C ABI stubs, `build_embree.{bat,sh}`.
- GitHub Actions matrix: `windows-latest`, `ubuntu-20.04`. Build artifact,
do NOT commit binaries (built in CI, attached to release).
- No C# changes. Verify compile only.
- Attribution files in place.

### PR2 — P/Invoke wrappers + smoke test
- `EmbreeNative.cs`, `EmbreeScene.cs`.
- One EditMode test: build Embree scene from a unit cube, query closest-point
from `(2, 0, 0)`, expect hit at `(0.5, 0, 0)`.
- Test gated by `UNITYMESHLAB_EMBREE`; CI sets the define after building the
binary. Test is a no-op on Mac and on PRs that don't touch native.

### PR3 — `IBvhBackend` refactor
- Extract interface, refactor existing callers (`TransferData`,
`GroupedShellTransfer`, `CoverageSplitSolver`) to use factory.
- Pure refactor: no Embree implementation yet. Existing managed path is the
only backend. Tests must pass unchanged.

### PR4 — Embree transfer backend
- Implement `EmbreeBvh : IBvhBackend`.
- Factory returns Embree if `UNITYMESHLAB_EMBREE` is set, else managed.
- Benchmark harness: 100k closest-point queries on a 200k-tri mesh.
Numbers in PR description (managed vs Embree, CI machine).

### PR5 — Embree AO backend
- `VertexAOBaker.Embree.cs`. Hook into `Backend.Embree` enum.
- Benchmark: 50k vertices × 64 samples on a 100k-tri scene.
Compare `.Cpu`, `.Gpu`, `.Embree`. Numbers in PR description.

### PR6 — SDF generator (separate effort)
- Standalone tool using `uml_embree_sdf_grid`.
- New `IUvTool` implementation in `Editor/Tools/SdfGeneratorTool.cs`.
- Out of scope for this plan beyond the C ABI hook.

### Future — macOS
- Add `macos-latest` to CI matrix.
- Build universal2 (arm64 + x86_64) Embree with `EMBREE_ISA_NEON2X=ON`.
- Drop `.dylib` to `Plugins/macOS/`.
- Extend `PostprocessorDefineManager` detect to cover macOS path.
- Requires Apple hardware for testing. Deferred until available.

## Acceptance per PR

Each PR must:
- Build cleanly on Windows and Linux CI.
- Not regress any existing test.
- Not change behaviour when `UNITYMESHLAB_EMBREE` is unset (verified by
running tests with the define stripped).
- Include before/after benchmark numbers for PR4 and PR5.

## Open questions

1. Static vs dynamic TBB link — decide in PR1 after measuring resulting
`umlab-embree.dll` size with each option.
2. Where to host prebuilt binaries: GitHub Releases attached to package
tags, or a separate `umlab-embree-binaries` repo. Affects how end users
install the package via UPM.
3. Should the Embree AO backend support multi-mesh scenes (occluders from
neighbouring meshes) in PR5, or single-mesh only and defer multi-mesh to
a follow-up? Current `.Gpu` baker is single-mesh; matching that is
simplest.
Loading