reduce preview edges

This commit is contained in:
Andrew Sink
2026-03-21 10:50:18 -04:00
parent 27306ed596
commit ad39191a9f
2 changed files with 15 additions and 8 deletions
+13 -6
View File
@@ -26,6 +26,8 @@ let previewDebounce = null;
// Boundary edge data texture for per-fragment falloff in bump-only preview
let _boundaryEdgeTex = null;
let _boundaryEdgeCount = 0;
let _falloffDirty = true; // recompute falloff on next updateFaceMask
let _falloffGeometry = null; // geometry the falloff was last computed for
// ── Exclusion state ───────────────────────────────────────────────────────────
let excludedFaces = new Set(); // triangle indices in currentGeometry
@@ -331,11 +333,11 @@ function wireEvents() {
linkSlider(rotationSlider, rotationVal, v => { settings.rotation = v; return Math.round(v); });
linkSlider(amplitudeSlider, amplitudeVal, v => { settings.amplitude = v; checkAmplitudeWarning(); return v.toFixed(2); });
amplitudeVal.addEventListener('change', checkAmplitudeWarning);
linkSlider(boundaryFalloffSlider, boundaryFalloffVal, v => { settings.boundaryFalloff = v; return v.toFixed(1); });
linkSlider(boundaryFalloffSlider, boundaryFalloffVal, v => { settings.boundaryFalloff = v; _falloffDirty = true; return v.toFixed(1); });
linkSlider(refineLenSlider, refineLenVal, v => { settings.refineLength = v; return v.toFixed(2); }, false);
linkSlider(maxTriSlider, maxTriVal, v => { settings.maxTriangles = v; return formatM(v); }, false);
linkSlider(bottomAngleLimitSlider, bottomAngleLimitVal, v => { settings.bottomAngleLimit = v; return v; });
linkSlider(topAngleLimitSlider, topAngleLimitVal, v => { settings.topAngleLimit = v; return v; });
linkSlider(bottomAngleLimitSlider, bottomAngleLimitVal, v => { settings.bottomAngleLimit = v; _falloffDirty = true; return v; });
linkSlider(topAngleLimitSlider, topAngleLimitVal, v => { settings.topAngleLimit = v; _falloffDirty = true; return v; });
linkSlider(seamBlendSlider, seamBlendVal, v => { settings.mappingBlend = v; return v.toFixed(2); });
linkSlider(seamBandWidthSlider, seamBandWidthVal, v => { settings.seamBandWidth = v; return v.toFixed(2); });
symmetricDispToggle.addEventListener('change', () => {
@@ -796,6 +798,7 @@ function handlePlaceOnFaceClick(e) {
function refreshExclusionOverlay() {
if (!currentGeometry) return;
_falloffDirty = true;
if (selectionMode) {
// Include Only mode: tint the complement (non-selected faces) with a pastel blue
// so the model stays visible against the dark background before any faces are painted.
@@ -1146,8 +1149,12 @@ function updateFaceMask(geometry) {
addFaceNormals(geometry);
}
computeBoundaryFalloffAttr(geometry, maskArr);
computeBoundaryEdges(geometry, maskArr);
if (_falloffDirty || geometry !== _falloffGeometry) {
computeBoundaryFalloffAttr(geometry, maskArr);
computeBoundaryEdges(geometry, maskArr);
_falloffDirty = false;
_falloffGeometry = geometry;
}
syncBoundaryEdgeUniforms();
}
@@ -1388,7 +1395,7 @@ function computeBoundaryEdges(geometry, userMaskArr) {
}
}
const MAX_EDGES = 512;
const MAX_EDGES = 64;
const edges = [];
for (const [key, faces] of edgeFaces) {
if (edges.length >= MAX_EDGES) break;
+2 -2
View File
@@ -248,7 +248,7 @@ const fragmentShader = /* glsl */`
// compute the distance from each pixel to the nearest boundary edge.
if (useDisplacement == 0 && boundaryFalloffDist > 0.001 && boundaryEdgeCount > 0) {
float minDist = boundaryFalloffDist;
for (int i = 0; i < 512; i++) {
for (int i = 0; i < 64; i++) {
if (i >= boundaryEdgeCount) break;
float uA = (float(i * 2) + 0.5) / boundaryEdgeTexWidth;
float uB = (float(i * 2 + 1) + 0.5) / boundaryEdgeTexWidth;
@@ -258,7 +258,7 @@ const fragmentShader = /* glsl */`
float abLen2 = dot(ab, ab);
float t = clamp(dot(vModelPos - ea, ab) / max(abLen2, 1e-10), 0.0, 1.0);
float d = length(vModelPos - (ea + t * ab));
minDist = min(minDist, d);
if (d < minDist) { minDist = d; if (d < 1e-4) break; }
}
maskBlend *= clamp(minDist / boundaryFalloffDist, 0.0, 1.0);
}