mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-30 12:21:05 +00:00
Write the documentation in plain ASCII
Only the degree sign is left, as a unit, which the gizmos already use.
This commit is contained in:
+31
-31
@@ -93,7 +93,7 @@ same order - only the positions of displaced vertices differ.
|
||||
coverage per original triangle comes straight off `TriangleSplittingData::triangles_to_split`.
|
||||
3. For each layer in slot order: deserialize its stored paint mask into a `TriangleSelector` against
|
||||
the **base mesh** (never against a previous layer's output), then
|
||||
`selector.get_facets_strict(ENFORCER)` → the painted patch. Two facts are exploited:
|
||||
`selector.get_facets_strict(ENFORCER)` -> the painted patch. Two facts are exploited:
|
||||
- `get_facets_strict()` returns the mesh's **entire** referenced vertex array regardless of which
|
||||
state was asked for - only `.indices` is filtered by state. So `get_facets_strict(ENFORCER)`
|
||||
and `get_facets_strict(NONE)` share identical vertex indexing, which is what lets boundary
|
||||
@@ -162,7 +162,7 @@ sampling a white (1.0) texel multiplies by exactly 1, i.e. leaves the layers bel
|
||||
Divide floors its divisor's magnitude at 0.05: a black texel samples to *exactly* zero, so the divisor
|
||||
really does hit zero in ordinary use, and an unbounded `1/0` would fling vertices thousands of mm away
|
||||
and poison the mesh's bounding box (and every plate/print-volume check downstream). The floor doubles as
|
||||
a cap on how far Divide can amplify the relief beneath it: at most 20×.
|
||||
a cap on how far Divide can amplify the relief beneath it: at most 20x.
|
||||
|
||||
The **lowest painted layer ignores its blend mode**: it has nothing beneath it, and Multiply/Divide
|
||||
against an implicit zero base would annihilate (or blow up) it. Enforced in
|
||||
@@ -179,7 +179,7 @@ texture samples per vertex and so has no single UV that represents it.
|
||||
- **Triplanar** (default) - samples the texture on all three world planes (`(y,z)`, `(x,z)`, `(x,y)`)
|
||||
and blends the three by the vertex's own normal raised to `TRIPLANAR_BLEND_SHARPNESS` (4). Hard-picking
|
||||
the single axis most aligned with the normal instead is discontinuous wherever that dominant axis
|
||||
flips: on a +X face the planar coordinate is `(y, z)`, on a −Y face it is `(x, z)`, so at the shared
|
||||
flips: on a +X face the planar coordinate is `(y, z)`, on a -Y face it is `(x, z)`, so at the shared
|
||||
edge `u` jumps. A weighted blend is continuous across the transition by construction, since the weight
|
||||
of the axis being left behind falls smoothly to zero. This removes the hard *seam*; some cross-fade
|
||||
blurring in the band right at a 90° edge is inherent to triplanar mapping. A genuinely seam-free wrap
|
||||
@@ -228,7 +228,7 @@ texture samples per vertex and so has no single UV that represents it.
|
||||
|
||||
`TextureDisplacementLayer::lscm_seam_edges` - undirected mesh-vertex-index edge pairs the unwrap is
|
||||
forced to cut along, on top of the dihedral-angle seams. `segment_into_charts()` takes a set of these
|
||||
(translated from mesh → compacted-patch numbering inside `compute_patch_unwrap()`) and refuses to
|
||||
(translated from mesh -> compacted-patch numbering inside `compute_patch_unwrap()`) and refuses to
|
||||
union two triangles across a marked edge whatever their angle. Both the unwrap cache key and the
|
||||
gizmo's `UVEditorState` include the seam list, so marking a seam (which leaves the paint mask
|
||||
untouched) still forces a re-solve. Like the paint masks, seams are mesh-index-space and so dropped on
|
||||
@@ -251,7 +251,7 @@ Two ways to write to it:
|
||||
drawn over the painted patch (`rebuild_uvcheck_mesh()`/`render_uvcheck_mesh()`, P3N3T2: `normal.x` =
|
||||
distortion, `tex_coord` = uv), pulled forward with a polygon offset. **Checker** samples a procedural
|
||||
checkerboard at the layer's uv (per-vertex for LSCM/ViewProjected, in-shader triplanar otherwise) -
|
||||
squares that stay square mean low distortion. **Distortion** colours each triangle blue→green→red by
|
||||
squares that stay square mean low distortion. **Distortion** colours each triangle blue->green->red by
|
||||
`log2(uv_area / surface_area)` centred on the patch's *median* stretch (so a globally-scaled unwrap
|
||||
reads as uniformly ideal and only relative stretch shows), averaged to vertices. A separate **Show mesh
|
||||
wireframe** toggle draws the whole volume's triangle edges, rebuilt only when the vertex count changes
|
||||
@@ -264,16 +264,16 @@ wireframe** toggle draws the whole volume's triangle edges, rebuilt only when th
|
||||
directly** rather than clamping the *coordinate* into range, which would smear the border row/column of
|
||||
pixels outward to infinity in every direction (streaky lines radiating out from the painted patch).
|
||||
|
||||
### Subdivision — two modes
|
||||
### Subdivision - two modes
|
||||
|
||||
**Uniform (`subdivide_mesh_uniform()`)** — whole-mesh, 1-to-4 split. Recursive edge-midpoint split with
|
||||
**Uniform (`subdivide_mesh_uniform()`)** - whole-mesh, 1-to-4 split. Recursive edge-midpoint split with
|
||||
a shared per-pass midpoint cache (keyed by sorted vertex-index pair) so triangles sharing an edge get
|
||||
the *same* new vertex - capped at `max_iterations` (default 6). Whole-mesh so it never leaves a
|
||||
T-junction, at the cost of densifying everywhere. Wired as a "Subdivide steps" slider (**0–5**, 0 =
|
||||
T-junction, at the cost of densifying everywhere. Wired as a "Subdivide steps" slider (**0-5**, 0 =
|
||||
no subdivision), Apply snaps back to 0. Drops texture-displacement paint (no remap) via the standard
|
||||
`save_painting()`/`set_mesh()`/`restore_painting()` dance; the other four channels are remapped.
|
||||
|
||||
**Adaptive (`subdivide_mesh_adaptive()`)** — refine **only the painted area**, by **Rivara longest-edge
|
||||
**Adaptive (`subdivide_mesh_adaptive()`)** - refine **only the painted area**, by **Rivara longest-edge
|
||||
bisection**, which is *conformal by construction*. Only **terminal** edges are ever bisected - an edge
|
||||
that is the longest edge of *every* triangle sharing it - which splits both those triangles along one
|
||||
shared midpoint at once, so a hanging node is never created. The edge to split for a triangle that wants
|
||||
@@ -325,8 +325,8 @@ a linear **ramp** needs no extra vertices (linear interpolation is exact for a r
|
||||
test: sample the combined displacement at the triangle's three edge midpoints *and its centroid*
|
||||
(sampling the interior is what catches a hill sitting inside a triangle, the blind spot of an edge-only
|
||||
test) and take the largest departure from the flat triangle's barycentric interpolation. Refine while
|
||||
that exceeds `chord_tolerance_mm` ("Detail (mm)"). Zero chord error on a ramp ⇒ untouched; high on a
|
||||
hill/ridge/noise ⇒ refined until captured. Same conformal machinery, so still crack-free. The
|
||||
that exceeds `chord_tolerance_mm` ("Detail (mm)"). Zero chord error on a ramp => untouched; high on a
|
||||
hill/ridge/noise => refined until captured. Same conformal machinery, so still crack-free. The
|
||||
per-triangle error is cached and recomputed only for the children of a split.
|
||||
|
||||
Four knobs bracket it, and all four matter:
|
||||
@@ -371,10 +371,10 @@ array is longer. `rebuild_shaded_preview_mesh()` and `rebuild_uvcheck_mesh()` th
|
||||
preview (stroke-end/slider-release) but from the **live** `TriangleSelector` state, not the flushed model
|
||||
facets, so it does not lag by a full model round-trip.
|
||||
|
||||
The perturbed normal is the analytic one for a height field `H = ±depth_mm · h(uv)` displaced along
|
||||
The perturbed normal is the analytic one for a height field `H = +/-depth_mm - h(uv)` displaced along
|
||||
`N` over any orthonormal surface tangent pair `T`/`B`:
|
||||
|
||||
N' = normalize(N − (dH/da)·T − (dH/db)·B), a = dot(p,T), b = dot(p,B)
|
||||
N' = normalize(N - (dH/da)-T - (dH/db)-B), a = dot(p,T), b = dot(p,B)
|
||||
|
||||
The two slopes have to be genuine **mm-per-mm** derivatives for the preview's apparent depth to match
|
||||
the bake's.
|
||||
@@ -389,28 +389,28 @@ the bake's.
|
||||
the CPU (`compute_layer_vertex_uvs()`, so island placement + tiling/rotation/offset are already folded
|
||||
in), and the perturbed normal is built with **Mikkelsen's method** ("Bump Mapping Unparametrized
|
||||
Surfaces on the GPU"): the surface gradient taken directly from the screen-space derivatives of the
|
||||
*sampled height* and position. **This makes no uv→mm scale assumption**, which is essential, because an
|
||||
*sampled height* and position. **This makes no uv->mm scale assumption**, which is essential, because an
|
||||
LSCM map is **conformal, not isometric**: it is globally area-scaled but the *local* mm-per-uv varies
|
||||
across the chart, so a single global `1/tiling_scale` factor gets the apparent depth wrong. `dFdx(h)`
|
||||
captures the true on-screen rate of change however the chart is stretched. This path is also what makes
|
||||
the fast preview follow the UV editor: move an island and its uv - hence its shading - moves with it
|
||||
(the mesh rebuilds on drag-end, `on_island_edited(finished)` → `rebuild_preview()` →
|
||||
(the mesh rebuilds on drag-end, `on_island_edited(finished)` -> `rebuild_preview()` ->
|
||||
`rebuild_shaded_preview_mesh()`). The branch is uniform and the paint weight gates by multiply, so the
|
||||
texture derivatives stay well defined. A triangle straddling a seam has a discontinuous uv → the
|
||||
`det≈0` guard skips it (a localised preview-only artifact, never in the bake).
|
||||
texture derivatives stay well defined. A triangle straddling a seam has a discontinuous uv -> the
|
||||
`det~0` guard skips it (a localised preview-only artifact, never in the bake).
|
||||
|
||||
**Parallax (triplanar path).** Perturbing the shading normal alone welds the pattern to the base surface:
|
||||
it does not slide as the camera orbits, and does not get deeper as `depth_mm` grows. The triplanar path
|
||||
therefore shades at the point the *displaced* surface would show at this pixel, found by **ray marching**
|
||||
(parallax occlusion mapping). A point at ray parameter `s`, i.e. `P + V·s` (`P` the base point, `V` the
|
||||
unit direction to the eye), sits at height `s·dot(V,n)` above the undisplaced surface. The displaced
|
||||
surface lives in a shell between the extreme values of `amp·(h − midlevel)` - taken from both ends of
|
||||
`h ∈ [0,1]`, so it holds for an inverted layer and a raised midlevel too, where the surface sits *below*
|
||||
(parallax occlusion mapping). A point at ray parameter `s`, i.e. `P + V-s` (`P` the base point, `V` the
|
||||
unit direction to the eye), sits at height `s-dot(V,n)` above the undisplaced surface. The displaced
|
||||
surface lives in a shell between the extreme values of `amp-(h - midlevel)` - taken from both ends of
|
||||
`h in [0,1]`, so it holds for an inverted layer and a raised midlevel too, where the surface sits *below*
|
||||
the undisplaced one. The march starts at the top of that shell, where the ray is outside the surface by
|
||||
construction, and steps inward until the ray height drops below the sampled height. That crossing *is*
|
||||
the visible point.
|
||||
|
||||
Solving `Q = P + V·(H(Q)/dot(V,n))` by fixed-point iteration instead is geometrically exact but the
|
||||
Solving `Q = P + V-(H(Q)/dot(V,n))` by fixed-point iteration instead is geometrically exact but the
|
||||
divisor goes to zero edge-on; the sample then lands a large fraction of a tile away and the iteration
|
||||
oscillates, which reads as a second, flat copy of the pattern ghosted over the real one. Clamping the
|
||||
step to one tile does not help - a tile-sized shift lands on the neighbouring tile, the same pattern
|
||||
@@ -420,7 +420,7 @@ enough that the relief still flattens as soon as the camera tilts. Marching has
|
||||
The hit is interpolated between the last two samples, which keeps `PARALLAX_STEPS` (24) affordable, and
|
||||
the whole march is skipped when sweeping the shell would move the sample point less than half a texel -
|
||||
the head-on case, so the common view pays almost nothing. The 140 variant samples with
|
||||
`textureLod(…, 0.0)` inside the loop, since implicit derivatives are undefined in non-uniform control
|
||||
`textureLod(..., 0.0)` inside the loop, since implicit derivatives are undefined in non-uniform control
|
||||
flow. Two uniforms exist for this: `midlevel` (parallax needs the real height, not just its derivative)
|
||||
and `eye_model_pos` (the camera in the volume's local frame).
|
||||
|
||||
@@ -457,17 +457,17 @@ but the bake samples from a **local-space** position, so the two have to be reco
|
||||
`view_project_right/up` can only express an *affine* projection - exact under an orthographic camera, but
|
||||
wrong under perspective, where the near end of a part projects larger than the far end and no pair of
|
||||
axes reproduces that. So the layer instead stores a full projective map (`view_project_matrix`, row-major
|
||||
3×4, `uv = (row0·p̃/row2·p̃, row1·p̃/row2·p̃)`), built like this:
|
||||
3x4, `uv = (row0-p/row2-p, row1-p/row2-p)`), built like this:
|
||||
|
||||
- `K = projection · view · (instance · volume)`, i.e. local → clip, the same product the renderer uses.
|
||||
- `K = projection - view - (instance - volume)`, i.e. local -> clip, the same product the renderer uses.
|
||||
Note `Camera::get_projection_matrix()` is typed `Transform3d` (nominally affine) but its perspective
|
||||
form explicitly writes a `(0, 0, −1, 0)` bottom row into the underlying 4×4, so `clip.w = −z_eye` is
|
||||
form explicitly writes a `(0, 0, -1, 0)` bottom row into the underlying 4x4, so `clip.w = -z_eye` is
|
||||
genuinely carried. The build therefore multiplies **`.matrix()` products** (plain `Matrix4d`), never
|
||||
`Transform3d` products, which would not compose that row correctly.
|
||||
- Window coordinates follow `igl::project`'s convention (as `CameraUtils::project` does), with y
|
||||
measured downward. Writing `uv = (win − rect_origin) / rect_size` makes u and v affine in
|
||||
measured downward. Writing `uv = (win - rect_origin) / rect_size` makes u and v affine in
|
||||
`ndc = clip.xyz / clip.w`; multiplying through by `clip.w` leaves a plain linear combination of `K`'s
|
||||
rows, which is exactly the 3×4 matrix - the perspective divide survives intact.
|
||||
rows, which is exactly the 3x4 matrix - the perspective divide survives intact.
|
||||
- `w > 0` is checked rather than divided blindly. A point behind the projector has `w < 0` and divides
|
||||
to a plausible-looking but **mirrored** uv - the classic way a projected decal reappears on the back
|
||||
of a model. `project_uv_projective()` returns false there and the caller treats it as no height.
|
||||
@@ -512,7 +512,7 @@ changes (`unwrap_changed` in `update_uv_editor()`).
|
||||
**Gestures** (canvas-owned, reported to the gizmo as incremental deltas via `IslandEditFn`): left-drag
|
||||
= move, right-drag or **R** = rotate (hold **Shift** to snap to 15° steps - quantised on the
|
||||
*cumulative* rotation, not each delta, so it doesn't judder, and accumulated incrementally so it
|
||||
survives crossing ±180°), **S** = scale (R/S modal, click/Enter to confirm, Esc to cancel), wheel =
|
||||
survives crossing +/-180°), **S** = scale (R/S modal, click/Enter to confirm, Esc to cancel), wheel =
|
||||
zoom about the cursor, middle-drag = pan, **Home**/**F** = frame all. Scale writes
|
||||
`TextureIsland::scale`; "Avg scale" (`average_island_scales()`) sets every island to the mean, so
|
||||
one island scaled by hand can be matched back to its neighbours' texel density. **Snap** (canvas-owned
|
||||
@@ -542,11 +542,11 @@ gizmo via `CommandFn`; view-only ones (Frame, Snap) it handles directly.
|
||||
- `src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp/.cpp` - the gizmo and its whole panel.
|
||||
- `src/slic3r/GUI/TextureLibrary.hpp/.cpp` - scans the shipped + user texture folders, imports an
|
||||
arbitrary image into the user folder (converting it to the 8-bit grayscale PNG libslic3r decodes),
|
||||
and loads a library file's bytes for a layer. The image→grayscale-PNG conversion lives here, on the
|
||||
and loads a library file's bytes for a layer. The image->grayscale-PNG conversion lives here, on the
|
||||
GUI side, because libslic3r has no image toolkit; both the import path and the "pick a shipped
|
||||
texture" path go through the same one function.
|
||||
- `resources/textures/displacement/*.png` - the 10 shipped height maps (Bricks, Grid, Hexagons,
|
||||
Knurl, Noise, Quilt, Studs, Waves, Weave, Wood Grain). All 512×512 8-bit grayscale and **seamless**
|
||||
Knurl, Noise, Quilt, Studs, Waves, Weave, Wood Grain). All 512x512 8-bit grayscale and **seamless**
|
||||
(each is periodic over the full image in both axes, so tiling shows no seam). Generated
|
||||
procedurally; the whole `resources/` tree is installed recursively by CMake, so a new folder under
|
||||
it ships with no build-system change.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Texture Displacement — Feature & Controls Guide
|
||||
# Texture Displacement - Feature & Controls Guide
|
||||
|
||||
Texture Displacement is a paint-style gizmo that stamps 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
|
||||
and turns them into real relief - engraved or embossed detail - either as a live preview or baked
|
||||
into actual mesh geometry. You paint where the texture applies, stack multiple textures as blended
|
||||
layers, choose how each is projected onto the surface, and (for the unwrap projection) lay the result
|
||||
out by hand in a dedicated 2D **UV Editor** pane.
|
||||
@@ -66,7 +66,7 @@ Choose *how* you paint. All three write into the **active layer's** mask.
|
||||
| **Face** | Click a single triangle to paint it. |
|
||||
| **Connected area** | Click to flood-fill a region; the **Angle threshold** slider limits how far the fill spreads across changes in surface angle. |
|
||||
|
||||
- **Select whole model** — marks the entire model as painted for the active layer, instead of
|
||||
- **Select whole model** - marks the entire model as painted for the active layer, instead of
|
||||
brushing it by hand.
|
||||
|
||||
---
|
||||
@@ -78,17 +78,17 @@ radio group; **Wireframe** is an independent toggle. Hover any icon for its tool
|
||||
|
||||
| View | Meaning |
|
||||
|------|---------|
|
||||
| **Normal** | The true displaced geometry — exactly what **Bake** produces. Rebuilt in the background. |
|
||||
| **Fast** | A GPU shaded approximation of the *active layer only*. No real geometry movement — quick to update, not exact. Best while tuning or dragging islands. |
|
||||
| **Normal** | The true displaced geometry - exactly what **Bake** produces. Rebuilt in the background. |
|
||||
| **Fast** | A GPU shaded approximation of the *active layer only*. No real geometry movement - quick to update, not exact. Best while tuning or dragging islands. |
|
||||
| **Checker** | A test grid painted over the unwrap so you can see stretching (squares stay square where the map isn't distorted). |
|
||||
| **Distortion** | A blue→green→red heatmap of how much each area is compressed or stretched in UV space. Needs the **Unwrap (LSCM)** projection. |
|
||||
| **Distortion** | A blue->green->red heatmap of how much each area is compressed or stretched in UV space. Needs the **Unwrap (LSCM)** projection. |
|
||||
| **Wireframe** | Overlays the mesh edges (white). Independent of the view above; in **Normal** view it sits on the displaced surface. |
|
||||
|
||||
---
|
||||
|
||||
## Auto update
|
||||
|
||||
**Auto update** (on by default) rebuilds the true displaced geometry as soon as *anything* changes —
|
||||
**Auto update** (on by default) rebuilds the true displaced geometry as soon as *anything* changes -
|
||||
painting, swapping textures, moving sliders. Turn it off on very heavy models to only rebuild when you
|
||||
release a slider (painting still updates on stroke end).
|
||||
|
||||
@@ -99,12 +99,12 @@ release a slider (painting still updates on stroke end).
|
||||
You can stack up to **8** texture layers. Each has its own independent paint mask, its own texture,
|
||||
and its own parameters, and they combine in slot order like layers in an image editor.
|
||||
|
||||
- **Add a layer** — the **+ icon** to the right of the *Texture layers* heading (reuses the tool icon
|
||||
- **Add a layer** - the **+ icon** to the right of the *Texture layers* heading (reuses the tool icon
|
||||
for now).
|
||||
- **Remove** — the button on each layer's header row.
|
||||
- **Active layer** — click a layer's header (or anywhere in its block) to make it active. The active
|
||||
- **Remove** - the button on each layer's header row.
|
||||
- **Active layer** - click a layer's header (or anywhere in its block) to make it active. The active
|
||||
layer is the one you paint into and the one whose block is tinted. Only one layer is active at a time.
|
||||
- **Erase all** — clears the active layer's paint.
|
||||
- **Erase all** - clears the active layer's paint.
|
||||
|
||||
Each layer shows a texture **picker** (large preview + name). Open it to choose from the shipped
|
||||
library or import your own image (any png/jpg/bmp; it's converted to an 8-bit grayscale height map and
|
||||
@@ -116,12 +116,12 @@ copied into your user texture folder so app updates can't overwrite it).
|
||||
|
||||
| Control | Range / options | What it does |
|
||||
|---------|-----------------|--------------|
|
||||
| **Depth (mm)** | 0.01–10 (log) | Maximum displacement along the surface normal. |
|
||||
| **Tile size (mm)** | 0.2–200 (log) | Physical size of one texture tile on the surface. |
|
||||
| **Rotation** | 0–360° | Rotates the texture on the surface. |
|
||||
| **Midlevel** | 0–10 | The grey level that means "don't move". At 0 the texture only pushes outward; raise it and darker texels cut *inward* (one map both embosses and engraves). 0.5 makes mid-grey neutral. |
|
||||
| **Smoothing** | 0–1 | Blurs the height texture before it displaces — rounds hard edges and removes speckle without needing a softer source image. |
|
||||
| **Edge smoothing** | checkbox + **Edge amount** 0–1 | Fades the relief to flat toward the *edge of the painted area*, so it blends into the surrounding surface. A small amount softens only a thin band at the very edge; the maximum flattens the whole painted face. |
|
||||
| **Depth (mm)** | 0.01-10 (log) | Maximum displacement along the surface normal. |
|
||||
| **Tile size (mm)** | 0.2-200 (log) | Physical size of one texture tile on the surface. |
|
||||
| **Rotation** | 0-360° | Rotates the texture on the surface. |
|
||||
| **Midlevel** | 0-10 | The grey level that means "don't move". At 0 the texture only pushes outward; raise it and darker texels cut *inward* (one map both embosses and engraves). 0.5 makes mid-grey neutral. |
|
||||
| **Smoothing** | 0-1 | Blurs the height texture before it displaces - rounds hard edges and removes speckle without needing a softer source image. |
|
||||
| **Edge smoothing** | checkbox + **Edge amount** 0-1 | Fades the relief to flat toward the *edge of the painted area*, so it blends into the surrounding surface. A small amount softens only a thin band at the very edge; the maximum flattens the whole painted face. |
|
||||
| **Invert** | checkbox | Flips the height map (peaks become valleys). |
|
||||
| **Blend** | Add / Subtract / Multiply / Divide | How this layer combines with the layers **below** it where they overlap. Add/Subtract pile relief on or carve it away; Multiply/Divide scale the relief underneath (a mask). The lowest painted layer is the **Base** and always behaves additively. |
|
||||
| **Tile** | checkbox + **Repeat / Mirrored repeat** | When off, the texture is placed once (a decal) instead of repeating. Mirrored repeat flips every other tile to hide seams. |
|
||||
@@ -149,16 +149,16 @@ How the 2D texture is wrapped onto the 3D painted area.
|
||||
|
||||
These appear when a layer uses **Unwrap (LSCM)**:
|
||||
|
||||
- **Seam angle** (5–90°) — edges sharper than this are cut so each piece lies flat. Lower cuts more
|
||||
- **Seam angle** (5-90°) - edges sharper than this are cut so each piece lies flat. Lower cuts more
|
||||
(less stretching, more seams); raise to keep more in one piece. A box's 90° corners are cut by
|
||||
default. *Ignored once you've marked any seam by hand* (your seams then define the pieces).
|
||||
- **Connect islands** (on by default) — lays the unwrap out as a **connected net**: pieces that share
|
||||
- **Connect islands** (on by default) - lays the unwrap out as a **connected net**: pieces that share
|
||||
an edge are unfolded next to each other (a cube becomes a joined net instead of six loose squares).
|
||||
They stay separate islands, so you can still move any of them by hand. Turn off for the classic
|
||||
packed-grid layout.
|
||||
- **Open UV editor** — shows the flattened unwrap in a side pane (see below). Opens *only* when you
|
||||
turn this on — it never pops up on its own.
|
||||
- **Mark seams** / **Path** / **Clear seams** — see [Seams](#seams).
|
||||
- **Open UV editor** - shows the flattened unwrap in a side pane (see below). Opens *only* when you
|
||||
turn this on - it never pops up on its own.
|
||||
- **Mark seams** / **Path** / **Clear seams** - see [Seams](#seams).
|
||||
- An **Unwrap: N islands, F faces, V verts** read-out tells you what the unwrap actually produced.
|
||||
|
||||
---
|
||||
@@ -166,9 +166,9 @@ These appear when a layer uses **Unwrap (LSCM)**:
|
||||
## The UV Editor
|
||||
|
||||
A dockable 2D pane (enable **Open UV editor** on an LSCM layer) showing the flattened unwrap over the
|
||||
height texture. Islands are the flattened pieces; you can rearrange them freely — nothing re-packs them
|
||||
height texture. Islands are the flattened pieces; you can rearrange them freely - nothing re-packs them
|
||||
behind your back. Moving an island updates the model **live** (in Fast view it tracks the cursor
|
||||
smoothly, via a shader uniform — no rebuild until you release).
|
||||
smoothly, via a shader uniform - no rebuild until you release).
|
||||
|
||||
### Navigation
|
||||
|
||||
@@ -185,7 +185,7 @@ smoothly, via a shader uniform — no rebuild until you release).
|
||||
| Select | Left-click an island |
|
||||
| Move | Left-drag |
|
||||
| Rotate | Right-drag, or press **R** then move the mouse (click/Enter to confirm, Esc to cancel) |
|
||||
| Rotate snapped | Hold **Shift** while rotating — snaps to **global** 15° marks (0/15/30…). A protractor dial with tick marks and the current angle is shown. |
|
||||
| Rotate snapped | Hold **Shift** while rotating - snaps to **global** 15° marks (0/15/30...). A protractor dial with tick marks and the current angle is shown. |
|
||||
| Scale | Press **S** then move the mouse (click/Enter to confirm, Esc to cancel) |
|
||||
| Undo / Redo | **Ctrl+Z** / **Ctrl+Shift+Z** or **Ctrl+Y** |
|
||||
|
||||
@@ -198,35 +198,35 @@ A **status line** along the bottom always names the current gesture and the shor
|
||||
| Button | Action |
|
||||
|--------|--------|
|
||||
| **Frame** | Frame all islands (same as Home). |
|
||||
| **Snap** | Toggle magnetic snapping — a dragged island sticks its boundary to a neighbour's when they come close. |
|
||||
| **Snap** | Toggle magnetic snapping - a dragged island sticks its boundary to a neighbour's when they come close. |
|
||||
| **Avg scale** | Give every island the same texel density (Blender's "Average Islands Scale"). |
|
||||
| **Cut** | Split the selected island across its long axis (useful for very long islands). |
|
||||
| **Join** | Unfold the selected island onto its nearest neighbour along their shared edge — keeps both as separate islands with their own borders. |
|
||||
| **Join** | Unfold the selected island onto its nearest neighbour along their shared edge - keeps both as separate islands with their own borders. |
|
||||
| **Unjoin** | Send the selected island back to its own packed position. |
|
||||
|
||||
> **Checker / Distortion in the UV editor:** selecting those View modes also colours the UV pane — a
|
||||
> checker background, or a per-island distortion heatmap — so you can judge stretch in 2D as well as
|
||||
> **Checker / Distortion in the UV editor:** selecting those View modes also colours the UV pane - a
|
||||
> checker background, or a per-island distortion heatmap - so you can judge stretch in 2D as well as
|
||||
> on the model.
|
||||
|
||||
---
|
||||
|
||||
## Seams
|
||||
|
||||
Seams are edges the unwrap is forced to cut along, on top of whatever the Seam angle cuts — the
|
||||
Seams are edges the unwrap is forced to cut along, on top of whatever the Seam angle cuts - the
|
||||
Blender "mark seam" workflow. They let you control exactly where the unwrap splits.
|
||||
|
||||
Enable **Mark seams** on an active LSCM layer, then:
|
||||
|
||||
- **Click an edge** on the model to mark it (it turns **red**); click a red edge again to unmark it.
|
||||
The edge under the cursor is highlighted **yellow** so you can see what a click will toggle.
|
||||
- **Path mode** (the **Path** checkbox) — for dense meshes where clicking each edge is tedious: click a
|
||||
- **Path mode** (the **Path** checkbox) - for dense meshes where clicking each edge is tedious: click a
|
||||
start point, then an end point, and the whole **shortest path** between them is seamed at once. It
|
||||
chains (each click extends from the last point); the start vertex is shown in **green**.
|
||||
- **Ctrl+drag** rotates/pans the camera while in seam mode.
|
||||
- **Clear seams** removes them all.
|
||||
|
||||
Once any seam is marked, the automatic Seam-angle cutting is disabled so *your* seams define the
|
||||
islands — pieces you leave un-seamed merge together.
|
||||
islands - pieces you leave un-seamed merge together.
|
||||
|
||||
---
|
||||
|
||||
@@ -245,20 +245,20 @@ Displacement can only move vertices that exist, so a coarse model needs more of
|
||||
|
||||
### Subdivide
|
||||
|
||||
Splits every triangle into four, **1–5 times** (each step roughly quadruples the triangle count).
|
||||
Splits every triangle into four, **1-5 times** (each step roughly quadruples the triangle count).
|
||||
|
||||
- **Subdivide steps** (1–5) — how many times to split.
|
||||
- **Preview subdivision** — shows the result as a **cyan wireframe** without changing the model.
|
||||
- **Apply** — commits the subdivision to the geometry.
|
||||
- **Done** — ends the preview and leaves the model as it is.
|
||||
- **Subdivide steps** (1-5) - how many times to split.
|
||||
- **Preview subdivision** - shows the result as a **cyan wireframe** without changing the model.
|
||||
- **Apply** - commits the subdivision to the geometry.
|
||||
- **Done** - ends the preview and leaves the model as it is.
|
||||
|
||||
### Remesh
|
||||
|
||||
Rebuilds the whole model with triangles close to a target edge length — evens out a mesh with wildly
|
||||
Rebuilds the whole model with triangles close to a target edge length - evens out a mesh with wildly
|
||||
varying triangle sizes (CGAL isotropic remeshing).
|
||||
|
||||
- **Target edge (mm)** — desired triangle edge length (seeded to the model's current average).
|
||||
- **Remesh** — splits the big triangles and merges the small ones to that size.
|
||||
- **Target edge (mm)** - desired triangle edge length (seeded to the model's current average).
|
||||
- **Remesh** - splits the big triangles and merges the small ones to that size.
|
||||
|
||||
> Both Subdivide-Apply and Remesh **replace the geometry** and clear any *not-yet-baked* paint on it
|
||||
> (already-baked relief is kept). If you had the mesh **Wireframe** on before, it stays on afterward.
|
||||
@@ -267,9 +267,9 @@ varying triangle sizes (CGAL isotropic remeshing).
|
||||
|
||||
## Baking & resetting
|
||||
|
||||
- **Bake** — converts the current preview into real, permanent mesh geometry, restricted to the
|
||||
painted area. Runs in the background; the button shows *Baking…* while it works.
|
||||
- **Erase all** — clears the active layer's paint.
|
||||
- **Bake** - converts the current preview into real, permanent mesh geometry, restricted to the
|
||||
painted area. Runs in the background; the button shows *Baking...* while it works.
|
||||
- **Erase all** - clears the active layer's paint.
|
||||
|
||||
Baking is the exact same algorithm as the **Normal** preview, so what you see is what you get.
|
||||
|
||||
@@ -277,7 +277,7 @@ Baking is the exact same algorithm as the **Normal** preview, so what you see is
|
||||
|
||||
## Controls reference
|
||||
|
||||
### Mouse — 3D view (while painting)
|
||||
### Mouse - 3D view (while painting)
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
@@ -285,7 +285,7 @@ Baking is the exact same algorithm as the **Normal** preview, so what you see is
|
||||
| Ctrl + drag | Rotate / pan the camera (works in seam mode too) |
|
||||
| Wheel | Zoom |
|
||||
|
||||
### Mouse & keys — UV Editor
|
||||
### Mouse & keys - UV Editor
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
@@ -314,7 +314,7 @@ Baking is the exact same algorithm as the **Normal** preview, so what you see is
|
||||
- **Paint first, then bake.** The preview is free to explore; only Bake changes the real mesh.
|
||||
- **Not enough detail?** Subdivide or Remesh before painting fine textures.
|
||||
- **Inward cuts** (high Midlevel + big Depth) can self-intersect on thin walls or sharp concave
|
||||
corners — keep Depth modest there.
|
||||
corners - keep Depth modest there.
|
||||
- **Fast vs Normal:** Fast preview only shades the relief and shows only the active layer; use it for quick
|
||||
tuning and smooth UV dragging, but trust **Normal**/**Bake** for the exact result.
|
||||
- **Topology changes drop unbaked paint.** Subdivide-Apply, Remesh, and Simplify replace the mesh, and
|
||||
|
||||
Reference in New Issue
Block a user