mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 14:20:58 +00:00
## Summary Adds a new paint-style **Texture Displacement** gizmo that stamps grayscale height-map textures onto a model's surface and turns them into real relief - engraved or embossed detail - either as a live preview or baked into actual mesh geometry. You paint where a texture applies, stack up to **8 blended texture layers** (image-editor semantics: Add / Subtract / Multiply / Divide), choose how each is projected onto the surface (Triplanar / Cylindrical / Spherical / LSCM unwrap / From-view), and - for the LSCM projection - lay the charts out by hand in a new dockable 2D **UV Editor** pane. Coarse models can be **Subdivided** or **Remeshed** first so there are enough vertices to carry fine detail, and the result is committed with **Bake**, restricted to the painted area only. The tool only ever affects the **painted** region; everything left unpainted keeps its original surface, and bake blends the relief seamlessly into it with no remeshing or hole-filling at the seam. --- ## User-facing features - **Paint the affected area** with Brush (circle/sphere), single-Face, or Connected-area flood fill; or **Select whole model** - reusing the existing `TriangleSelector` / `FacetsAnnotation` painting machinery, one full mask per layer slot. - **Up to 8 texture layers**, each with its own paint mask, texture, and parameters, combined in slot order like image layers. - **Per-layer controls:** Depth, Tile size, Rotation, Midlevel (bidirectional emboss/engrave), Smoothing, Edge smoothing, Invert, Blend mode, Tile (Repeat / Mirrored-repeat / decal), and Projection. - **Projection methods:** Triplanar (blended, seam-free across sharp edges), Cylindrical, Spherical, **Unwrap (LSCM)** - a real CGAL conformal parameterization - and **From view** (slide-projector decals). - **UV Editor pane** for LSCM layers: move / rotate / scale / snap / cut / join islands, average texel density, Checker and Distortion overlays, manual mark- seam workflow, live model update while dragging. - **View modes:** Normal (true displaced geometry = what Bake produces), Fast (GPU bump-shaded approximation of the active layer), Checker, Distortion heatmap, and an independent Wireframe toggle. - **Mesh prep:** Subdivide (1–5* uniform 1->4 split) with cyan-wireframe preview, and CGAL isotropic **Remesh** to a target edge length. - **Texture library:** 10 shipped seamless 512×512 grayscale height maps, plus import of any PNG/JPG/BMP (converted to an 8-bit grayscale map and copied into the user data dir so app updates can't clobber it). - **Bake** runs in the background (off the UI thread); the preview is free to explore and only Bake changes the real mesh. --- ## How it works (implementation) - **Bake is accumulate-then-displace and topology-preserving.** The output mesh has exactly the input's vertices and triangles in the same order; only displaced vertex positions differ. Each layer is evaluated against the **base mesh** and folded per-vertex into a shared accumulator via its blend mode, then every touched vertex moves once along its precomputed undisplaced normal. This replaced an earlier sequential re-mesh-per-layer design that was the root cause of the "second layer never applies" bug and made blend modes impossible. - **Boundary vertices are pinned.** Any vertex shared with an unpainted triangle is never displaced, which is what keeps bakes seamless with zero remeshing. - **LSCM unwrap** uses a new `MeshBoolean::cgal::parameterize_lscm()` built on CGAL's already-vendored `Surface_mesh_parameterization` package - **no new external dependency**. - **Fast GPU preview** perturbs the shading normal from the height gradient (analytic mm-per-mm slope for triplanar; Mikkelsen's screen-space-derivative method for the conformal LSCM path), so apparent depth matches the bake. - **Background jobs:** preview compute and bake both run off the UI thread on the shared job worker (queued, not `replace_job`, so a preview never cancels an in-flight bake); a generation counter discards stale results. - **UV Editor** shares the app's single real `wxGLContext` and reuses the registered `flat`/`flat_texture` shaders; island drags update one affine matrix per island rather than re-uploading geometry. --- ## Backward compatibility & constraints - **Feature is fully gated behind the new gizmo** - it adds no new default behavior and does not touch existing slicing, profiles, or defaults. Models that never open the tool are unaffected. - **Cross-platform** - pure `libslic3r` / `libslic3r_gui` / `libslic3r_cgal` code; no new dependency and no `deps/` rebuild. (Built and tested on Windows; no platform-specific APIs introduced.) - **`.3mf` compatibility:** **baked** relief round-trips fine, since it becomes ordinary mesh geometry via the existing serialization path. **Unbaked** paint masks and layer definitions are **not yet serialized** - see Limitations. No existing project data is affected. --- ## Testing Unit tests in `tests/libslic3r/test_texture_displacement.cpp` - **run and passing** (7 cases, 116 assertions). Coverage: - `decode_height_texture` round-trip - Empty-layer no-op - Full-cube uniform displacement - Boundary-vertex pinning on a hand-built fan mesh - Regression: a **second layer over the same area actually contributes** (the bug the bake rewrite fixed) - Table-driven check of all four blend modes - The lowest painted layer ignoring its blend mode `BUILD_TESTS` is `OFF` in the checked-in cache; enable to run: ```bash cmake -S . -B build -DBUILD_TESTS=ON cmake --build build --config Release --target libslic3r_tests -- -m ./build/tests/libslic3r/Release/libslic3r_tests.exe "[TextureDisplacement]" --order rand ``` ---