diff options
Diffstat (limited to 'public/bluebey-studio/src/clip.js')
| -rw-r--r-- | public/bluebey-studio/src/clip.js | 92 |
1 files changed, 55 insertions, 37 deletions
diff --git a/public/bluebey-studio/src/clip.js b/public/bluebey-studio/src/clip.js index d94e8e4..b5b03f4 100644 --- a/public/bluebey-studio/src/clip.js +++ b/public/bluebey-studio/src/clip.js @@ -117,57 +117,75 @@ function makeGuide() { } export function createClipper({ scene, renderer, model }) { - const plane = new THREE.Plane(); - const guide = makeGuide(); - const occluder = makeWall(); - scene.add(guide); - scene.add(occluder); // A little larger than the character: big enough to read as a wall, small // enough not to cover the whole viewport. const guideSpan = Math.max(model.size.x, model.size.y, model.size.z) * 1.5; + const FROM = new THREE.Vector3(0, 0, 1); // the plane the quad starts in + + function makeSlot() { + const occluder = makeWall(); + const guide = makeGuide(); + scene.add(guide); + scene.add(occluder); + return { occluder, guide, normal: new THREE.Vector3(0, 0, 1) }; + } + // Two walls. Each slot keeps its own rectangle, so the two are independent. + const slots = [makeSlot(), makeSlot()]; /** - * @param {object} wall `state.render.wall` + * @param {Array<object>} walls up to two `state.render.wall` settings, in slot + * order. + * @param {{x?:number,y?:number,z?:number}} [offset] the character's own + * translation. A wall's position is stored *relative to the character*, so + * adding this makes the walls travel with the body when it is moved. * - * The guide is drawn only when `wall.guide` is on, which is also when the plane + * The guide is drawn only when `wall.guide` is on, which is also when the wall * can be grabbed in the viewport. Off, the wall is invisible: the cut still * applies, so you can see the character half-hidden with nothing in the way. */ - function apply(wall) { - if (wall?.on !== true) { - occluder.visible = false; - guide.visible = false; - return; - } - - const { normal, constant } = wallPlane(wall); - plane.set(new THREE.Vector3(normal[0], normal[1], normal[2]), constant); - - const point = new THREE.Vector3(wall.x ?? 0, wall.y ?? 0, wall.z ?? 0); - const span = guideSpan * Math.max(0.05, wall.size ?? 1); - // The wall and its guide are the same rectangle, turned to face along the - // plane's normal: the wall is the occluder, the guide is the tinted copy that - // is shown only while placing. - for (const mesh of [occluder, guide]) { - mesh.quaternion.setFromUnitVectors(new THREE.Vector3(0, 0, 1), plane.normal); - mesh.scale.setScalar(span); - } - occluder.position.copy(point); - occluder.visible = true; - guide.position.copy(point).addScaledVector(plane.normal, GUIDE_EPSILON); - guide.visible = wall.guide === true; + function apply(walls, offset) { + const list = Array.isArray(walls) ? walls : [walls]; + const ox = offset?.x ?? 0; + const oy = offset?.y ?? 0; + const oz = offset?.z ?? 0; + slots.forEach((slot, index) => { + const wall = list[index]; + if (!wall || wall.on !== true) { + slot.occluder.visible = false; + slot.guide.visible = false; + return; + } + const x = (wall.x ?? 0) + ox; + const y = (wall.y ?? 0) + oy; + const z = (wall.z ?? 0) + oz; + const { normal } = wallPlane({ yaw: wall.yaw, tilt: wall.tilt, x, y, z }); + slot.normal.set(normal[0], normal[1], normal[2]); + const span = guideSpan * Math.max(0.05, wall.size ?? 1); + // The wall and its guide are the same rectangle, turned to face along the + // plane's normal: the wall is the occluder, the guide is the tinted copy + // that is shown only while placing. + for (const mesh of [slot.occluder, slot.guide]) { + mesh.quaternion.setFromUnitVectors(FROM, slot.normal); + mesh.scale.setScalar(span); + } + slot.occluder.position.set(x, y, z); + slot.occluder.visible = true; + slot.guide.position.set(x, y, z).addScaledVector(slot.normal, GUIDE_EPSILON); + slot.guide.visible = wall.guide === true; + }); } return { - plane, - guide, - occluder, + guides: slots.map((slot) => slot.guide), + occluders: slots.map((slot) => slot.occluder), apply, dispose() { - for (const mesh of [guide, occluder]) { - mesh.geometry.dispose(); - mesh.material.dispose(); - mesh.removeFromParent(); + for (const slot of slots) { + for (const mesh of [slot.guide, slot.occluder]) { + mesh.geometry.dispose(); + mesh.material.dispose(); + mesh.removeFromParent(); + } } }, }; |
