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 ``` ---
OrcaSlicer tests
Building, running and writing tests is documented on the wiki, under How to Test.
Two files here rather than there, because coding agents only read what is in the repository: