add volume rendering and use that for sla by default now

This commit is contained in:
Stewart Allen 2026-05-19 19:42:55 -04:00
commit 3be111af43
2 changed files with 77 additions and 10 deletions

View file

@ -212,6 +212,42 @@ export class Layers {
} }
} }
/**
* Add closed polygons as filled Z volumes.
* By default, the polygon Z is treated as the volume center. Pass
* { base:true } to treat polygon Z as the bottom face instead.
* @param {Polygon|Array<Polygon>} polys - Closed polygon(s), with inners preserved as voids
* @param {object} [options] - Options: {height, z, base, outline}
* @returns {Layers} This instance for chaining
*/
addZVolume(polys, options) {
const opts = options || {};
const height = opts.height || 1;
const faces = this.current.faces;
polys = Array.isArray(polys) ? polys.clone(true) : [ polys.clone(true) ];
for (let poly of polys) {
if (poly.open || poly.length < 3) {
continue;
}
let z = opts.z !== undefined ? opts.z : poly.getZ(),
zoff = opts.base ? z : z - height / 2,
volume = poly.setZ(0).extrude(height, { zadd: zoff });
faces.appendAll(volume);
if (opts.outline) {
this.addPolys([
poly.clone(true).setZ(zoff),
poly.clone(true).setZ(zoff + height)
]);
}
}
return this;
}
/** /**
* Add 2D polyline paths with width (usually FDM extrusion paths). * Add 2D polyline paths with width (usually FDM extrusion paths).
* Creates flat ribbons with vertex normals for lighting. * Creates flat ribbons with vertex normals for lighting.

View file

@ -245,36 +245,67 @@ export function sla_slice(settings, widget, onupdate, ondone) {
}); });
}; };
const SLA_RENDER_THICK = true;
function doRender(widget) { function doRender(widget) {
widget.slices.forEach(slice => { widget.slices.forEach(slice => {
const render = slice.output(), lopacity = 0.6, line = 0x010101; const render = slice.output(),
height = slice.height || 0.05,
lopacity = SLA_RENDER_THICK ? 1 : 0.6,
line = 0x010101;
if (slice.unioned) { if (slice.unioned) {
slice.unioned.forEach(poly => { slice.unioned.forEach(poly => {
poly = poly.clone(true);//.move(widget.track.pos); poly = poly.clone(true);//.move(widget.track.pos);
render renderSlicePoly(render, "layers", poly, {
.setLayer("layers", { line, face: 0x0099cc, lopacity }) line,
.addAreas([poly], { outline: true }); face: 0x0099cc,
lopacity,
height
});
}); });
} else if (slice.tops) { } else if (slice.tops) {
slice.tops.forEach(top => { slice.tops.forEach(top => {
let poly = top.poly;//.clone(true).move(widget.track.pos); let poly = top.poly;//.clone(true).move(widget.track.pos);
render renderSlicePoly(render, "layers", poly, {
.setLayer("layers", { line, face: 0xfcba03, lopacity }) line,
.addAreas([poly], { outline: true }); face: 0xfcba03,
lopacity,
height
});
}); });
} }
if (slice.supports) { if (slice.supports) {
slice.supports.forEach(poly => { slice.supports.forEach(poly => {
render renderSlicePoly(render, "support", poly, {
.setLayer("support", { line, face: 0xfcba03, lopacity }) line,
.addAreas([poly], { outline: true }); face: 0xfcba03,
lopacity,
height
});
}); });
} }
}); });
} }
function renderSlicePoly(render, layer, poly, options) {
let { line, face, lopacity, height } = options;
render.setLayer(layer, {
line,
face,
lopacity,
opacity: SLA_RENDER_THICK ? 1 : undefined
});
if (SLA_RENDER_THICK) {
render.addZVolume([poly], { height, outline: false });
} else {
render.addAreas([poly], { outline: true });
}
}
function computeSupports(widget, process, progress) { function computeSupports(widget, process, progress) {
let slices = widget.slices, let slices = widget.slices,
baseIndex = widget.lastraft ? widget.lastraft.index : 0, baseIndex = widget.lastraft ? widget.lastraft.index : 0,