parallelize widget shadow generation 2x faster
This commit is contained in:
parent
dda5107810
commit
f81e002766
5 changed files with 74 additions and 16 deletions
|
|
@ -1,5 +1,6 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { decode } from '../core/codec.js';
|
||||
import { util as mesh_util } from '../../mesh/util.js';
|
||||
import { tool as mesh_tool } from '../../mesh/tool.js';
|
||||
import { verticesToPoints } from '../../geo/points.js';
|
||||
|
|
@ -12,6 +13,7 @@ const sharedArrayClass = self.SharedArrayBuffer || undefined;
|
|||
const hasSharedArrays = sharedArrayClass ? true : false;
|
||||
const solid_opacity = 1.0;
|
||||
const groups = [];
|
||||
const debug_shadow = false;
|
||||
|
||||
let nextId = 0;
|
||||
|
||||
|
|
@ -739,8 +741,9 @@ class Widget {
|
|||
// the stacks are then used to produce shadowlines
|
||||
#ensureShadowCache() {
|
||||
if (this.cache.shadow) {
|
||||
return;
|
||||
return this.cache.shadow;
|
||||
}
|
||||
if (debug_shadow) console.time('shadow buckets');
|
||||
const geo = this.getGeoVertices({ unroll: true, translate: true });
|
||||
const length = geo.length;
|
||||
const bounds = this.getBoundingBox();
|
||||
|
|
@ -762,15 +765,54 @@ class Widget {
|
|||
stack[z].push(a, b, c);
|
||||
}
|
||||
}
|
||||
this.cache.shadow = stack;
|
||||
if (debug_shadow) console.timeEnd('shadow buckets');
|
||||
return this.cache.shadow = stack;
|
||||
}
|
||||
|
||||
async computeShadowStack(zlist, progress) {
|
||||
let shadow_stack = this.cache.shadow_stack;
|
||||
if (!shadow_stack) {
|
||||
shadow_stack = this.cache.shadow_stack = {};
|
||||
}
|
||||
let work = self.kiri_worker;
|
||||
let stack = this.#ensureShadowCache();
|
||||
let plist = [];
|
||||
if (debug_shadow) console.time('seed minion buckets');
|
||||
work.minions.broadcast('cam_shadow_stack', stack);
|
||||
if (debug_shadow) console.timeEnd('seed minion buckets');
|
||||
let pinc = 1 / zlist.length;
|
||||
let pval = 0;
|
||||
for (let z of zlist) {
|
||||
let p = work.minions.queueAsync({
|
||||
cmd: 'cam_shadow_z',
|
||||
z: z - 0.005,
|
||||
t: z + 1
|
||||
}).then(reply => {
|
||||
shadow_stack[z - 0.005] = decode(reply.data);
|
||||
pval += pinc;
|
||||
progress(pval);
|
||||
});
|
||||
plist.push(p);
|
||||
}
|
||||
await Promise.all(plist);
|
||||
work.minions.broadcast('cam_shadow_stack', { clear: true });
|
||||
}
|
||||
|
||||
computeShadowAtZ(z, ztop, cached) {
|
||||
return this.#computeShadowAt(z, ztop, cached);
|
||||
}
|
||||
|
||||
// union triangles > z (opt cap < ztop) into polygon(s)
|
||||
// slice the triangle stack matchingg z then union the results
|
||||
#computeShadowAt(z, ztop) {
|
||||
this.#ensureShadowCache();
|
||||
#computeShadowAt(z, ztop, cached) {
|
||||
let shadow_stack = this.cache.shadow_stack;
|
||||
if (shadow_stack && shadow_stack[z]) {
|
||||
return shadow_stack[z];
|
||||
}
|
||||
let label = `compute shadow ${z.round(2)}`;
|
||||
if (debug_shadow) console.time(label);
|
||||
const found = [];
|
||||
const stack = this.cache.shadow;
|
||||
const stack = cached ?? this.#ensureShadowCache();
|
||||
let minZ = Math.floor(z);
|
||||
let maxZ = Math.ceil(z);
|
||||
let slices = [];
|
||||
|
|
@ -832,6 +874,7 @@ class Widget {
|
|||
polys = POLY.offset(polys, 0.01);
|
||||
polys = POLY.offset(polys, -0.01);
|
||||
|
||||
if (debug_shadow) console.timeEnd(label);
|
||||
return polys;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ export class OpIndex extends CamOp {
|
|||
}
|
||||
|
||||
weight() {
|
||||
return 0.1;
|
||||
return 3;
|
||||
}
|
||||
|
||||
async slice() {
|
||||
async slice(progress) {
|
||||
let { op, state } = this;
|
||||
|
||||
if (!state.isIndexed) {
|
||||
|
|
@ -37,7 +37,7 @@ export class OpIndex extends CamOp {
|
|||
updateSlicer();
|
||||
|
||||
// recompute shadow from new widget geometry
|
||||
await computeShadows();
|
||||
await computeShadows(progress);
|
||||
}
|
||||
|
||||
prepare(ops, progress) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class OpShadow extends CamOp {
|
|||
}
|
||||
|
||||
weight() {
|
||||
return 0.1;
|
||||
return 3;
|
||||
}
|
||||
|
||||
async slice(progress) {
|
||||
|
|
@ -50,6 +50,9 @@ class OpShadow extends CamOp {
|
|||
tzindex = [ ];
|
||||
}
|
||||
|
||||
// distributed pre-fill shadow layer cache
|
||||
await widget.computeShadowStack(tzindex, prog => progress(prog / 2, 'shadow'));
|
||||
|
||||
// terrain is the "shadow stack" where index 0 = top of part
|
||||
// thus array.length -1 = bottom of part
|
||||
for (let i=0; i<tzindex.length; i++) {
|
||||
|
|
@ -65,7 +68,7 @@ class OpShadow extends CamOp {
|
|||
.setLayer("shadow", {line: 0x888800, thin: true })
|
||||
.addPolys(shadow, { thin: true });
|
||||
}
|
||||
progress(i / tzindex.length);
|
||||
progress(0.5 + i / tzindex.length, 'shadow');
|
||||
}
|
||||
|
||||
if (devel && slices.length) {
|
||||
|
|
|
|||
|
|
@ -261,12 +261,10 @@ export async function cam_slice(settings, widget, onupdate, ondone) {
|
|||
return slicer = state.slicer = new cam_slicer(widget, opts);
|
||||
}
|
||||
|
||||
async function computeShadows() {
|
||||
console.time('computeShadows');
|
||||
await new OPS.shadow(state, { type: "shadow", silent: true }).slice(progress => {
|
||||
// console.log('reshadowing', progress.round(3));
|
||||
});
|
||||
console.timeEnd('computeShadows');
|
||||
async function computeShadows(progress) {
|
||||
console.time('compute shadow');
|
||||
await new OPS.shadow(state, { type: "shadow", xsilent: true }).slice(progress);
|
||||
console.timeEnd('compute shadow');
|
||||
}
|
||||
|
||||
function setToolDiam(toolDiam) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { base } from '../../geo/base.js';
|
|||
import { codec, encode, encodePointArray } from '../core/codec.js';
|
||||
import { doTopShells } from '../mode/fdm/post.js';
|
||||
import { newPoint } from '../../geo/point.js';
|
||||
import { newWidget } from '../core/widget.js';
|
||||
import { polygons as POLY } from '../../geo/polygons.js';
|
||||
import { sliceZ, sliceConnect } from '../../geo/slicer.js';
|
||||
import { Slicer as cam_slicer } from '../mode/cam/slicer_cam.js';
|
||||
|
|
@ -317,5 +318,18 @@ const funcs = self.minion = {
|
|||
const topo4 = Object.assign(new Topo4(), cache.lathe);
|
||||
const heights = topo4.lathePath(stmp, tool);
|
||||
reply({ seq, heights });
|
||||
},
|
||||
|
||||
// cam widget shadow
|
||||
|
||||
cam_shadow_stack(data, seq) {
|
||||
cache.shadow_stack = data.clear ? undefined : data;
|
||||
},
|
||||
|
||||
cam_shadow_z(data, seq) {
|
||||
let polys = newWidget().computeShadowAtZ(data.z, data.t, cache.shadow_stack);
|
||||
let coded = codec.encode(polys);
|
||||
reply({ seq, data: coded });
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue