feat: add surface exclusions panel and functionality

- Introduced a new section in the UI for surface exclusions, allowing users to exclude triangles from displacement using brush and bucket fill tools.
- Implemented brush type switching (single and radius) and radius control for the brush tool.
- Added functionality for bucket fill with a threshold angle to control the fill area.
- Integrated exclusion weights into the displacement algorithm to ensure excluded faces are handled correctly during subdivision.
- Created adjacency and centroid calculations for triangles to support the bucket fill operation.
- Developed overlay geometries for visual feedback on excluded faces and hover previews.
- Enhanced the CSS for the new exclusion tools and their layout in the UI.
This commit is contained in:
CNCKitchen
2026-03-17 14:35:45 +01:00
parent f87b935b9a
commit 1d3e756245
7 changed files with 730 additions and 32 deletions
+62 -1
View File
@@ -109,7 +109,7 @@
</button>
<div class="lock-line"></div>
</div>
<div class="form-row slider-row">
<label for="scale-v">Scale V</label>
<input type="range" id="scale-v" min="0" max="1000" step="1" value="500" />
@@ -153,6 +153,67 @@
<p class="hint">0° = no masking. Surfaces within this angle of horizontal will not be textured.</p>
</section>
<!-- Surface Exclusions -->
<section class="panel-section">
<h2>Surface Exclusions</h2>
<!-- Tool buttons -->
<div class="excl-tools">
<button id="excl-brush-btn" class="excl-tool-btn" title="Brush: paint triangles to exclude" aria-pressed="false">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h2c1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z"/>
<path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h2c1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z"/>
</svg>
Brush
</button>
<button id="excl-bucket-btn" class="excl-tool-btn" title="Bucket fill: flood-fill surface up to a threshold angle" aria-pressed="false">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M19 11V4a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9"/>
<path d="M13 17h8m-4-4 4 4-4 4"/>
</svg>
Fill
</button>
<button id="excl-erase-toggle" class="excl-tool-btn" title="Toggle: mark or erase mode" aria-pressed="false">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21"/>
<path d="M22 21H7"/>
<path d="m5 11 9 9"/>
</svg>
Erase
</button>
</div>
<!-- Brush type switcher (shown only when Brush is active) -->
<div id="excl-brush-type-row" class="form-row hidden">
<label>Type</label>
<div class="excl-seg">
<button id="excl-brush-single" class="excl-seg-btn active">Single</button>
<button id="excl-brush-radius-btn" class="excl-seg-btn">Radius</button>
</div>
</div>
<!-- Radius slider (shown when Brush + Radius) -->
<div id="excl-radius-row" class="form-row slider-row hidden">
<label for="excl-brush-radius-slider">Radius</label>
<input type="range" id="excl-brush-radius-slider" min="0.1" max="50" step="0.1" value="5" />
<input type="number" class="val" id="excl-brush-radius-val" value="5" min="0.1" max="50" step="0.1" />
</div>
<!-- Bucket threshold (shown when Fill is active) -->
<div id="excl-threshold-row" class="form-row slider-row hidden">
<label for="excl-threshold-slider" title="Maximum dihedral angle between adjacent triangles for the fill to cross">Max angle</label>
<input type="range" id="excl-threshold-slider" min="0" max="180" step="1" value="30" />
<input type="number" class="val" id="excl-threshold-val" value="30" min="0" max="180" step="1" />
</div>
<!-- Footer: count + clear -->
<div class="excl-footer">
<span id="excl-count" class="excl-count">0 faces excluded</span>
<button id="excl-clear-btn" class="excl-clear-btn">Clear All</button>
</div>
<p class="hint">Excluded surfaces appear orange and will not receive displacement during export.</p>
</section>
<!-- Export -->
<section class="panel-section">
<h2>Export</h2>