aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/clip.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/bluebey-studio/src/clip.js')
-rw-r--r--public/bluebey-studio/src/clip.js92
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();
+ }
}
},
};