@adatechnology/game-characters-three 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +91 -18
- package/dist/index.global.js +457 -110
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +458 -110
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.global.js
CHANGED
|
@@ -5221,7 +5221,7 @@ var GameCharactersThree = (() => {
|
|
|
5221
5221
|
});
|
|
5222
5222
|
}
|
|
5223
5223
|
const neckLen = 0.14 + Math.max(0, P.neck);
|
|
5224
|
-
|
|
5224
|
+
const neck = cut.head ? void 0 : add(U, CYL(0.058, 0.068, neckLen, SEG), skinM, 0, 1.63 + Math.max(0, P.neck) / 2, 0);
|
|
5225
5225
|
const headG = new THREE.Group();
|
|
5226
5226
|
headG.position.set(0, 1.64 + P.neck, P.headFwd || 0);
|
|
5227
5227
|
headG.rotation.x = P.headX;
|
|
@@ -5428,6 +5428,7 @@ var GameCharactersThree = (() => {
|
|
|
5428
5428
|
if (o.userData.flap) flaps.push(o);
|
|
5429
5429
|
});
|
|
5430
5430
|
const rig = { flaps, dangles: arms.filter((a) => a.el.userData.dangle), type: spec.type || "Lento", fig, upper, headG, arms, legs, P, ph: spec.phase ?? options.random() * 6, dropBase: fig.position.y, leanBase: P.lean, hxBase: P.headX };
|
|
5431
|
+
if (neck) Object.defineProperty(rig, "neck", { value: neck });
|
|
5431
5432
|
if (spec.lying) {
|
|
5432
5433
|
root.rotation.x = -PI / 2;
|
|
5433
5434
|
root.position.set(0, 0.16 * P.s, 0.9 * P.s);
|
|
@@ -8165,7 +8166,8 @@ var GameCharactersThree = (() => {
|
|
|
8165
8166
|
const makeKit = () => options.createKit ? options.createKit({ penetration: settings.penetration, deathRule: settings.deathRule }) : createCharacters({ ...options.packs ? { packs: options.packs } : {}, penetration: settings.penetration, damage: { deathRule: settings.deathRule } });
|
|
8166
8167
|
let kit = makeKit();
|
|
8167
8168
|
let undead = options.createUndead ? options.createUndead(kit) : null;
|
|
8168
|
-
|
|
8169
|
+
let stream = createRng(options.seed ?? 1);
|
|
8170
|
+
const random = () => stream();
|
|
8169
8171
|
let seedCounter = 100;
|
|
8170
8172
|
let host = null;
|
|
8171
8173
|
let three = null;
|
|
@@ -8545,6 +8547,14 @@ var GameCharactersThree = (() => {
|
|
|
8545
8547
|
wounds = createWounds(lent.THREE, { random, scene: scene2, groundAt: (x, z) => lent.groundAt(x, z), ...bridge ? { bridge } : {}, ...sound ? { sound } : {} });
|
|
8546
8548
|
for (const entry of entries.values()) trackEntry(entry);
|
|
8547
8549
|
const stopChange = lent.bench?.onChange(onChange);
|
|
8550
|
+
const stopReset = lent.onReset?.(() => {
|
|
8551
|
+
stream = createRng(options.seed ?? 1);
|
|
8552
|
+
seedCounter = 100;
|
|
8553
|
+
time = 0;
|
|
8554
|
+
selected = null;
|
|
8555
|
+
lastCrossed = 0;
|
|
8556
|
+
lastEnergy = 1;
|
|
8557
|
+
});
|
|
8548
8558
|
const stopEvents = lent.on((event) => {
|
|
8549
8559
|
if (event.type !== "explosion") return;
|
|
8550
8560
|
for (const entry of entries.values()) {
|
|
@@ -8569,6 +8579,7 @@ var GameCharactersThree = (() => {
|
|
|
8569
8579
|
});
|
|
8570
8580
|
return () => {
|
|
8571
8581
|
stopChange?.();
|
|
8582
|
+
stopReset?.();
|
|
8572
8583
|
stopEvents();
|
|
8573
8584
|
stopFrame();
|
|
8574
8585
|
clearOverlays();
|
|
@@ -8637,12 +8648,272 @@ var GameCharactersThree = (() => {
|
|
|
8637
8648
|
shirtColor: "3d5a73"
|
|
8638
8649
|
};
|
|
8639
8650
|
|
|
8651
|
+
// src/first-person/ik.ts
|
|
8652
|
+
var solveTwoBone = (root, target, upper, lower, pole, out) => {
|
|
8653
|
+
const line = out.line.copy(target).sub(root);
|
|
8654
|
+
let distance3 = line.length();
|
|
8655
|
+
if (distance3 < 1e-6) line.set(0, 0, -1);
|
|
8656
|
+
else line.divideScalar(distance3);
|
|
8657
|
+
const min = Math.abs(upper - lower) + 1e-4;
|
|
8658
|
+
const max = upper + lower - 1e-4;
|
|
8659
|
+
out.clamped = distance3 > max || distance3 < min;
|
|
8660
|
+
distance3 = Math.min(max, Math.max(min, distance3));
|
|
8661
|
+
const along = (distance3 * distance3 + upper * upper - lower * lower) / (2 * distance3);
|
|
8662
|
+
const across = Math.sqrt(Math.max(0, upper * upper - along * along));
|
|
8663
|
+
const side = out.side.copy(pole);
|
|
8664
|
+
side.addScaledVector(line, -side.dot(line));
|
|
8665
|
+
if (side.lengthSq() < 1e-8) side.set(0, 1, 0).addScaledVector(line, -line.y);
|
|
8666
|
+
if (side.lengthSq() < 1e-8) side.set(1, 0, 0);
|
|
8667
|
+
side.normalize();
|
|
8668
|
+
out.joint.copy(root).addScaledVector(line, along).addScaledVector(side, across);
|
|
8669
|
+
out.end.copy(root).addScaledVector(line, distance3);
|
|
8670
|
+
return out;
|
|
8671
|
+
};
|
|
8672
|
+
var createTwoBone = (THREE) => ({ joint: new THREE.Vector3(), end: new THREE.Vector3(), clamped: false, line: new THREE.Vector3(), side: new THREE.Vector3() });
|
|
8673
|
+
|
|
8674
|
+
// src/player/arm-reach.ts
|
|
8675
|
+
var ARM_REACH = {
|
|
8676
|
+
/** The elbow never straightens past this bend (a locked elbow reads as a stick). */
|
|
8677
|
+
elbowMin: 0.12,
|
|
8678
|
+
/** Full flexion of the elbow. */
|
|
8679
|
+
elbowMax: 2.5,
|
|
8680
|
+
/** The wrist bends (flexion, extension, deviation) up to this angle from the line of the forearm (flexion reaches about 80 degrees). */
|
|
8681
|
+
wristBend: 1.3,
|
|
8682
|
+
/** The forearm turns (pronation and supination) up to this angle about its own axis. */
|
|
8683
|
+
wristTwist: 1.6,
|
|
8684
|
+
/** The most the chest turns to bring the support shoulder toward a far hand. */
|
|
8685
|
+
chestTurn: 0.6,
|
|
8686
|
+
/** The most a shoulder blade slides toward a far hand (protraction and elevation together). */
|
|
8687
|
+
protraction: 0.11,
|
|
8688
|
+
/** A hand is within reach below this fraction of the arm's length. */
|
|
8689
|
+
slack: 0.96,
|
|
8690
|
+
/** Where the elbow points: down and out from the body, a little back (body space, x outward). */
|
|
8691
|
+
elbowPole: [0.55, -1, -0.25],
|
|
8692
|
+
/** The support arm's elbow: under the gun, hardly out of the body (the first-person arms' `elbowPoleLeft`), so the forearm meets the handguard nearer the aim's line. */
|
|
8693
|
+
elbowPoleSupport: [0.1, -1, -0.2],
|
|
8694
|
+
/** From the wrist joint to the middle of the palm, metres of the body. */
|
|
8695
|
+
palm: 0.042,
|
|
8696
|
+
/** In a view the elbow keeps at least this interior bend where a hand is out of reach, right then left (the first-person arms' numbers). */
|
|
8697
|
+
viewBend: [1.35, 0.95],
|
|
8698
|
+
/** In a view a hand stays this far before a surface, metres. */
|
|
8699
|
+
contactMargin: 5e-3,
|
|
8700
|
+
/** In a view a hand is never nearer than this to the eye, metres. */
|
|
8701
|
+
contactNearest: 0.12,
|
|
8702
|
+
/** How far in front of the eye a surface is looked for, metres. */
|
|
8703
|
+
contactProbe: 1.4,
|
|
8704
|
+
/** How far a hand reaches forward of its middle at least (the thickness of the palm), and per metre of fingers pointing ahead. */
|
|
8705
|
+
contactPalm: 0.03,
|
|
8706
|
+
/** From the middle of the palm to the fingertips. */
|
|
8707
|
+
contactFingers: 0.085
|
|
8708
|
+
};
|
|
8709
|
+
var createArmReach = (THREE, rig, hands) => {
|
|
8710
|
+
const arms = {
|
|
8711
|
+
R: { g: rig.arms[1].g, el: rig.arms[1].el, hand: hands.R, outward: -1 },
|
|
8712
|
+
L: { g: rig.arms[0].g, el: rig.arms[0].el, hand: hands.L, outward: 1 }
|
|
8713
|
+
};
|
|
8714
|
+
const upper = rig.upper;
|
|
8715
|
+
const handBasis = {
|
|
8716
|
+
R: new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(new THREE.Vector3(0, -1, 0), new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 0, -1))).invert(),
|
|
8717
|
+
L: new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(new THREE.Vector3(0, -1, 0), new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 1))).invert()
|
|
8718
|
+
};
|
|
8719
|
+
const saved = {
|
|
8720
|
+
twist: 0,
|
|
8721
|
+
arms: { R: { position: new THREE.Vector3(), g: new THREE.Quaternion(), el: new THREE.Quaternion(), hand: new THREE.Quaternion() }, L: { position: new THREE.Vector3(), g: new THREE.Quaternion(), el: new THREE.Quaternion(), hand: new THREE.Quaternion() } }
|
|
8722
|
+
};
|
|
8723
|
+
let applied = false;
|
|
8724
|
+
const bone = createTwoBone(THREE);
|
|
8725
|
+
const v = { shoulder: new THREE.Vector3(), elbow: new THREE.Vector3(), wrist: new THREE.Vector3(), palm: new THREE.Vector3(), target: new THREE.Vector3(), pole: new THREE.Vector3(), a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };
|
|
8726
|
+
const q = { hand: new THREE.Quaternion(), parent: new THREE.Quaternion(), body: new THREE.Quaternion(), local: new THREE.Quaternion(), swing: new THREE.Quaternion(), twist: new THREE.Quaternion(), rest: new THREE.Quaternion() };
|
|
8727
|
+
const basis = new THREE.Matrix4();
|
|
8728
|
+
const camera = { position: new THREE.Vector3(), quaternion: new THREE.Quaternion(), inverse: new THREE.Quaternion(), probe: new THREE.Vector3(), forward: new THREE.Vector3(), fingers: new THREE.Vector3(), hand: new THREE.Quaternion() };
|
|
8729
|
+
let bendLimit = null;
|
|
8730
|
+
const yAxis = new THREE.Vector3(0, 1, 0);
|
|
8731
|
+
const lengthsOf = (arm) => {
|
|
8732
|
+
const scale = arm.g.getWorldScale(v.a).y;
|
|
8733
|
+
return { upper: arm.el.position.length() * scale, fore: arm.hand.position.length() * scale, palm: ARM_REACH.palm * scale };
|
|
8734
|
+
};
|
|
8735
|
+
const limitOf = (side, upperLength, fore) => {
|
|
8736
|
+
if (!bendLimit) return (upperLength + fore) * ARM_REACH.slack;
|
|
8737
|
+
return Math.sqrt(upperLength * upperLength + fore * fore + 2 * upperLength * fore * Math.cos(bendLimit[side === "R" ? 0 : 1]));
|
|
8738
|
+
};
|
|
8739
|
+
const wristOf = (side, pose, palm) => {
|
|
8740
|
+
q.hand.set(...pose.quaternion).multiply(handBasis[side]);
|
|
8741
|
+
v.palm.set(...pose.position);
|
|
8742
|
+
v.wrist.copy(v.palm).addScaledVector(v.a.set(0, -1, 0).applyQuaternion(q.hand), -palm);
|
|
8743
|
+
};
|
|
8744
|
+
const turnChest = (pose) => {
|
|
8745
|
+
const { upper: up, fore, palm } = lengthsOf(arms.L);
|
|
8746
|
+
wristOf("L", pose, palm);
|
|
8747
|
+
const excess = arms.L.g.getWorldPosition(v.shoulder).distanceTo(v.wrist) - limitOf("L", up, fore);
|
|
8748
|
+
if (excess <= 0) return;
|
|
8749
|
+
const chestRadius = Math.hypot(arms.L.g.position.x, arms.L.g.position.z) * arms.L.g.getWorldScale(v.a).y;
|
|
8750
|
+
upper.rotation.y -= Math.min(ARM_REACH.chestTurn, excess / Math.max(0.05, chestRadius));
|
|
8751
|
+
upper.updateMatrixWorld(true);
|
|
8752
|
+
};
|
|
8753
|
+
const protract = (arm, limit) => {
|
|
8754
|
+
const excess = arm.g.getWorldPosition(v.shoulder).distanceTo(v.wrist) - limit;
|
|
8755
|
+
if (excess <= 0) return;
|
|
8756
|
+
const parent = arm.g.parent;
|
|
8757
|
+
v.b.copy(v.wrist).sub(v.shoulder).normalize().multiplyScalar(Math.min(excess, ARM_REACH.protraction)).add(v.shoulder);
|
|
8758
|
+
arm.g.position.copy(parent.worldToLocal(v.b));
|
|
8759
|
+
arm.g.updateMatrixWorld(true);
|
|
8760
|
+
};
|
|
8761
|
+
const limitWrist = (local) => {
|
|
8762
|
+
const projection = v.c.set(local.x, local.y, local.z).projectOnVector(yAxis);
|
|
8763
|
+
q.twist.set(projection.x, projection.y, projection.z, local.w).normalize();
|
|
8764
|
+
const twistAngle = 2 * Math.atan2(q.twist.y, q.twist.w);
|
|
8765
|
+
const swing = q.swing.copy(local).multiply(q.twist.invert());
|
|
8766
|
+
const swingAngle = 2 * Math.acos(Math.min(1, Math.abs(swing.w)));
|
|
8767
|
+
if (swingAngle > ARM_REACH.wristBend) swing.slerp(q.rest.identity(), 1 - ARM_REACH.wristBend / swingAngle);
|
|
8768
|
+
const clampedTwist = Math.max(-ARM_REACH.wristTwist, Math.min(ARM_REACH.wristTwist, Math.atan2(Math.sin(twistAngle), Math.cos(twistAngle))));
|
|
8769
|
+
return local.copy(swing).multiply(q.twist.setFromAxisAngle(yAxis, clampedTwist));
|
|
8770
|
+
};
|
|
8771
|
+
const reach = (side, pose) => {
|
|
8772
|
+
const arm = arms[side];
|
|
8773
|
+
const { upper: up, fore, palm } = lengthsOf(arm);
|
|
8774
|
+
wristOf(side, pose, palm);
|
|
8775
|
+
protract(arm, limitOf(side, up, fore));
|
|
8776
|
+
arm.g.getWorldPosition(v.shoulder);
|
|
8777
|
+
upper.getWorldQuaternion(q.body);
|
|
8778
|
+
const pole = side === "L" ? ARM_REACH.elbowPoleSupport : ARM_REACH.elbowPole;
|
|
8779
|
+
v.pole.set(pole[0] * arm.outward, pole[1], pole[2]).applyQuaternion(q.body);
|
|
8780
|
+
const lockLimit = Math.sqrt(up * up + fore * fore + 2 * up * fore * Math.cos(ARM_REACH.elbowMin));
|
|
8781
|
+
const most = bendLimit ? Math.min(lockLimit, limitOf(side, up, fore)) : lockLimit;
|
|
8782
|
+
const least = Math.sqrt(up * up + fore * fore + 2 * up * fore * Math.cos(ARM_REACH.elbowMax));
|
|
8783
|
+
const line = v.c.copy(v.wrist).sub(v.shoulder);
|
|
8784
|
+
const distance3 = Math.min(most, Math.max(least, line.length()));
|
|
8785
|
+
v.target.copy(v.shoulder).addScaledVector(line.normalize(), distance3);
|
|
8786
|
+
solveTwoBone(v.shoulder, v.target, up, fore, v.pole, bone);
|
|
8787
|
+
const along = v.a.copy(bone.joint).sub(v.shoulder).normalize();
|
|
8788
|
+
const forearm = v.b.copy(bone.end).sub(bone.joint).normalize();
|
|
8789
|
+
const fold = v.c.copy(forearm).addScaledVector(along, -forearm.dot(along));
|
|
8790
|
+
if (fold.lengthSq() < 1e-8) fold.copy(v.pole).addScaledVector(along, -v.pole.dot(along)).negate();
|
|
8791
|
+
fold.normalize();
|
|
8792
|
+
const yWorld = v.elbow.copy(along).negate();
|
|
8793
|
+
basis.makeBasis(v.pole.crossVectors(yWorld, fold), yWorld, fold);
|
|
8794
|
+
arm.g.parent.getWorldQuaternion(q.parent);
|
|
8795
|
+
arm.g.quaternion.setFromRotationMatrix(basis).premultiply(q.parent.invert());
|
|
8796
|
+
arm.el.rotation.set(-Math.acos(Math.max(-1, Math.min(1, along.dot(forearm)))), 0, 0);
|
|
8797
|
+
arm.g.updateMatrixWorld(true);
|
|
8798
|
+
const reached = arm.hand.getWorldPosition(v.a).sub(v.shoulder).normalize();
|
|
8799
|
+
q.swing.setFromUnitVectors(reached, v.b.copy(v.target).sub(v.shoulder).normalize());
|
|
8800
|
+
arm.g.parent.getWorldQuaternion(q.parent);
|
|
8801
|
+
arm.g.quaternion.premultiply(q.parent).premultiply(q.swing).premultiply(q.parent.invert());
|
|
8802
|
+
arm.g.updateMatrixWorld(true);
|
|
8803
|
+
arm.el.getWorldQuaternion(q.parent);
|
|
8804
|
+
arm.hand.quaternion.copy(limitWrist(q.local.copy(q.parent.invert()).multiply(q.hand)));
|
|
8805
|
+
};
|
|
8806
|
+
const keepOutside = (pose, outside) => {
|
|
8807
|
+
const place = v.a.set(...pose.position).sub(camera.position).applyQuaternion(camera.inverse);
|
|
8808
|
+
camera.probe.set(place.x, place.y, 0).applyQuaternion(camera.quaternion).add(camera.position);
|
|
8809
|
+
camera.forward.set(0, 0, -1).applyQuaternion(camera.quaternion);
|
|
8810
|
+
const distance3 = outside.contact([camera.probe.x, camera.probe.y, camera.probe.z], [camera.forward.x, camera.forward.y, camera.forward.z], ARM_REACH.contactProbe);
|
|
8811
|
+
if (distance3 === null) return pose;
|
|
8812
|
+
camera.hand.set(...pose.quaternion).premultiply(camera.inverse);
|
|
8813
|
+
const ahead = Math.max(ARM_REACH.contactPalm, -camera.fingers.set(1, 0, 0).applyQuaternion(camera.hand).z * ARM_REACH.contactFingers);
|
|
8814
|
+
const limit = Math.max(outside.nearest ?? ARM_REACH.contactNearest, distance3 - ahead - (outside.margin ?? ARM_REACH.contactMargin));
|
|
8815
|
+
if (-place.z <= limit) return pose;
|
|
8816
|
+
place.z = -limit;
|
|
8817
|
+
place.applyQuaternion(camera.quaternion).add(camera.position);
|
|
8818
|
+
return { ...pose, position: [place.x, place.y, place.z] };
|
|
8819
|
+
};
|
|
8820
|
+
const save = () => {
|
|
8821
|
+
saved.twist = upper.rotation.y;
|
|
8822
|
+
for (const side of ["R", "L"]) {
|
|
8823
|
+
const arm = arms[side];
|
|
8824
|
+
const into = saved.arms[side];
|
|
8825
|
+
into.position.copy(arm.g.position);
|
|
8826
|
+
into.g.copy(arm.g.quaternion);
|
|
8827
|
+
into.el.copy(arm.el.quaternion);
|
|
8828
|
+
into.hand.copy(arm.hand.quaternion);
|
|
8829
|
+
}
|
|
8830
|
+
};
|
|
8831
|
+
return {
|
|
8832
|
+
apply(targets, view) {
|
|
8833
|
+
if (!targets || !targets.R && !targets.L) return;
|
|
8834
|
+
save();
|
|
8835
|
+
applied = true;
|
|
8836
|
+
upper.updateWorldMatrix(true, true);
|
|
8837
|
+
let { R, L } = targets;
|
|
8838
|
+
bendLimit = view ? view.reachBend ?? ARM_REACH.viewBend : null;
|
|
8839
|
+
if (view?.keepOutside) {
|
|
8840
|
+
view.camera.updateWorldMatrix(true, false);
|
|
8841
|
+
view.camera.matrixWorld.decompose(camera.position, camera.quaternion, v.a);
|
|
8842
|
+
camera.inverse.copy(camera.quaternion).invert();
|
|
8843
|
+
if (R) R = keepOutside(R, view.keepOutside);
|
|
8844
|
+
if (L) L = keepOutside(L, view.keepOutside);
|
|
8845
|
+
}
|
|
8846
|
+
if (L && R) turnChest(L);
|
|
8847
|
+
if (R) reach("R", R);
|
|
8848
|
+
if (L) reach("L", L);
|
|
8849
|
+
bendLimit = null;
|
|
8850
|
+
},
|
|
8851
|
+
restore() {
|
|
8852
|
+
if (!applied) return;
|
|
8853
|
+
applied = false;
|
|
8854
|
+
upper.rotation.y = saved.twist;
|
|
8855
|
+
for (const side of ["R", "L"]) {
|
|
8856
|
+
const arm = arms[side];
|
|
8857
|
+
const from = saved.arms[side];
|
|
8858
|
+
arm.g.position.copy(from.position);
|
|
8859
|
+
arm.g.quaternion.copy(from.g);
|
|
8860
|
+
arm.el.quaternion.copy(from.el);
|
|
8861
|
+
arm.hand.quaternion.copy(from.hand);
|
|
8862
|
+
}
|
|
8863
|
+
}
|
|
8864
|
+
};
|
|
8865
|
+
};
|
|
8866
|
+
|
|
8867
|
+
// src/player/head-hiding.ts
|
|
8868
|
+
var isDrawable = (object2) => {
|
|
8869
|
+
const flagged = object2;
|
|
8870
|
+
return Boolean(flagged.isMesh || flagged.isSprite || flagged.isPoints);
|
|
8871
|
+
};
|
|
8872
|
+
var createHeadHider = (roots) => {
|
|
8873
|
+
let isHiding = false;
|
|
8874
|
+
let viewCamera = null;
|
|
8875
|
+
const drawables = [];
|
|
8876
|
+
for (const root of roots) root.traverse((object2) => isDrawable(object2) && drawables.push(object2));
|
|
8877
|
+
for (const drawable of drawables) {
|
|
8878
|
+
const previousBefore = drawable.onBeforeRender;
|
|
8879
|
+
const previousAfter = drawable.onAfterRender;
|
|
8880
|
+
let saved = [];
|
|
8881
|
+
drawable.onBeforeRender = (renderer, scene2, camera, geometry, material, group) => {
|
|
8882
|
+
previousBefore.call(drawable, renderer, scene2, camera, geometry, material, group);
|
|
8883
|
+
if (!isHiding || camera !== viewCamera) return;
|
|
8884
|
+
const drawn = Array.isArray(drawable.material) ? drawable.material : [material];
|
|
8885
|
+
saved = drawn.map((entry) => ({ material: entry, colorWrite: entry.colorWrite, depthWrite: entry.depthWrite }));
|
|
8886
|
+
for (const entry of drawn) {
|
|
8887
|
+
entry.colorWrite = false;
|
|
8888
|
+
entry.depthWrite = false;
|
|
8889
|
+
}
|
|
8890
|
+
};
|
|
8891
|
+
drawable.onAfterRender = (renderer, scene2, camera, geometry, material, group) => {
|
|
8892
|
+
previousAfter.call(drawable, renderer, scene2, camera, geometry, material, group);
|
|
8893
|
+
for (const flags of saved) {
|
|
8894
|
+
flags.material.colorWrite = flags.colorWrite;
|
|
8895
|
+
flags.material.depthWrite = flags.depthWrite;
|
|
8896
|
+
}
|
|
8897
|
+
saved = [];
|
|
8898
|
+
};
|
|
8899
|
+
}
|
|
8900
|
+
return {
|
|
8901
|
+
setView(mode, camera) {
|
|
8902
|
+
isHiding = mode === "first" && camera !== null;
|
|
8903
|
+
viewCamera = camera;
|
|
8904
|
+
}
|
|
8905
|
+
};
|
|
8906
|
+
};
|
|
8907
|
+
|
|
8640
8908
|
// src/player/avatar.ts
|
|
8641
8909
|
var TWO_PI2 = Math.PI * 2;
|
|
8642
8910
|
var MAX_GAIT = 1.4;
|
|
8643
8911
|
var CLIP_BLEND = 0.12;
|
|
8644
8912
|
var CLIP_CASCADE = 5;
|
|
8645
8913
|
var FALL_SECONDS2 = 0.3;
|
|
8914
|
+
var BUILDER_EYE = [0, 1.815, 0.16];
|
|
8915
|
+
var EYE_OFFSET = [0, -0.068, 0];
|
|
8916
|
+
var EYE_BOB = 0.5;
|
|
8646
8917
|
var HIP_HEIGHT = 0.95;
|
|
8647
8918
|
var WALK_ARM = 0.28;
|
|
8648
8919
|
var WALK_BOB = 0.035;
|
|
@@ -8652,7 +8923,11 @@ var GameCharactersThree = (() => {
|
|
|
8652
8923
|
var REST_ARM_Z = 0.18;
|
|
8653
8924
|
var CROUCH = { thigh: -0.95, thighWalk: 0.3, shin: 1.9, lean: 0.25, drop: -0.35 };
|
|
8654
8925
|
var AIMED = { shoulder: -1.42, perAim: 0.85, swing: 0.02, zRight: -0.54, zLeft: 0.36, elbowRight: -0.04, elbowLeft: -0.12 };
|
|
8926
|
+
var SIT = { thigh: -1.5, lean: -0.08, arm: -0.45, armZ: 0.12, elbow: -0.75 };
|
|
8927
|
+
var LIE = { knee: 0.08, armZ: 0.12, elbow: -0.1 };
|
|
8655
8928
|
var DOWN = { thighWalk: 0.5, shinSwing: 0.85, shinBend: 1.3, armHigh: -2.8, armLow: -0.35, armWave: 0.3, armZ: 0.5, armZWave: 0.3, tilt: 1.5, roll: 0.3, hipY: 0.16, hipZ: 0.6, hipZFlip: 1.2 };
|
|
8929
|
+
var DOOR_SHOULDER = 1.42;
|
|
8930
|
+
var DOOR_ARM = 0.62;
|
|
8656
8931
|
var HAND_OFFSET = { x: 0, y: -0.33, z: 0.04 };
|
|
8657
8932
|
var hexOf = (value) => typeof value === "string" ? Number.parseInt(value, 16) : value;
|
|
8658
8933
|
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
@@ -8682,6 +8957,8 @@ var GameCharactersThree = (() => {
|
|
|
8682
8957
|
const fallSeconds = options.fallSeconds ?? FALL_SECONDS2;
|
|
8683
8958
|
const smooth = options.cascade ?? true;
|
|
8684
8959
|
const clipCascade = options.clipCascade ?? CLIP_CASCADE;
|
|
8960
|
+
const eyeBob = options.eyeBob ?? EYE_BOB;
|
|
8961
|
+
const eyeOffset = options.eyeOffset ?? EYE_OFFSET;
|
|
8685
8962
|
const root = new THREE.Group();
|
|
8686
8963
|
const tilt = new THREE.Group();
|
|
8687
8964
|
tilt.add(body);
|
|
@@ -8733,6 +9010,7 @@ var GameCharactersThree = (() => {
|
|
|
8733
9010
|
const built = buildHand({ THREE, add: addMesh, hg, handM: handMaterial, s: side, detailed: true });
|
|
8734
9011
|
hands.push({ side, hg, fingers: built.fingers, th: built.th });
|
|
8735
9012
|
});
|
|
9013
|
+
const armReach = createArmReach(THREE, rig, { R: hands.find((hand) => hand.side < 0).hg, L: hands.find((hand) => hand.side > 0).hg });
|
|
8736
9014
|
const setHandGrip = (hand, grip, wristX = 0) => {
|
|
8737
9015
|
hand.fingers.forEach((finger, j) => {
|
|
8738
9016
|
finger.rotation.z = -hand.side * grip * (j % 2 ? 1.1 : 0.9);
|
|
@@ -8740,7 +9018,23 @@ var GameCharactersThree = (() => {
|
|
|
8740
9018
|
if (hand.th) hand.th.rotation.z = -hand.side * (0.32 + grip * 0.25);
|
|
8741
9019
|
hand.hg.rotation.x = wristX;
|
|
8742
9020
|
};
|
|
9021
|
+
const eyeSocket = new THREE.Object3D();
|
|
9022
|
+
eyeSocket.name = "eye";
|
|
9023
|
+
eyeSocket.position.set(BUILDER_EYE[0] + eyeOffset[0], BUILDER_EYE[1] + eyeOffset[1], BUILDER_EYE[2] + eyeOffset[2]);
|
|
9024
|
+
rig.headG.children[0].add(eyeSocket);
|
|
9025
|
+
const headHider = createHeadHider([rig.headG, ...rig.neck ? [rig.neck] : []]);
|
|
9026
|
+
const eyeLocal = new THREE.Vector3();
|
|
9027
|
+
let bob = 0;
|
|
9028
|
+
let hipWithoutBob = null;
|
|
8743
9029
|
const legRestX = rig.legs.map((leg) => leg.g.position.x);
|
|
9030
|
+
const legLengths = (() => {
|
|
9031
|
+
const thigh = rig.legs[0].g;
|
|
9032
|
+
const shin = rig.legs[0].kn;
|
|
9033
|
+
root.updateMatrixWorld(true);
|
|
9034
|
+
const hipY = thigh.getWorldPosition(new THREE.Vector3()).y;
|
|
9035
|
+
const kneeY = shin.getWorldPosition(new THREE.Vector3()).y;
|
|
9036
|
+
return { hipBelowTrunk: HIP_HEIGHT - hipY, thigh: hipY - kneeY, shin: kneeY - new THREE.Box3().setFromObject(shin).min.y };
|
|
9037
|
+
})();
|
|
8744
9038
|
const legSide = (index) => index === 0 ? 1 : -1;
|
|
8745
9039
|
let cycles = 0;
|
|
8746
9040
|
let time = 0;
|
|
@@ -8799,10 +9093,29 @@ var GameCharactersThree = (() => {
|
|
|
8799
9093
|
...strain ? { legL: -0.5, legR: 0.4, kneeL: 0.55, kneeR: 0.08, drop: -0.05 } : {}
|
|
8800
9094
|
};
|
|
8801
9095
|
};
|
|
9096
|
+
const doorPose = (door) => {
|
|
9097
|
+
const { phase, progress } = door;
|
|
9098
|
+
const on = phase === "reach" ? progress : phase === "release" ? 1 - progress : 1;
|
|
9099
|
+
const swing = phase === "swing" ? progress : phase === "release" ? 1 : 0;
|
|
9100
|
+
const shake = phase === "rattle" ? Math.sin(time * 55) * 0.06 * (1 - progress) : 0;
|
|
9101
|
+
const drop = clamp((DOOR_SHOULDER - door.height) / DOOR_ARM, -0.9, 1);
|
|
9102
|
+
const low = clamp((0.75 - door.height) / 0.5, 0, 1);
|
|
9103
|
+
const raise = -Math.acos(clamp(drop, -1, 1)) * on - 0.35 * low * on;
|
|
9104
|
+
const elbow = door.pull ? -0.35 - 0.75 * swing : -0.95 + 0.75 * swing;
|
|
9105
|
+
return {
|
|
9106
|
+
armR: raise + shake,
|
|
9107
|
+
armRz: REST_ARM_Z * (1 - on) + 0.05 * on,
|
|
9108
|
+
elbR: -0.12 + (elbow + 0.12) * on,
|
|
9109
|
+
armLz: -REST_ARM_Z,
|
|
9110
|
+
elbL: -0.12,
|
|
9111
|
+
lean: ((door.pull ? -0.06 : 0.1) * swing + 0.35 * low) * on,
|
|
9112
|
+
headX: 0.06 * on + 0.2 * low * on
|
|
9113
|
+
};
|
|
9114
|
+
};
|
|
8802
9115
|
const holdingPose = (gait, itemUse) => {
|
|
8803
|
-
const
|
|
9116
|
+
const bob2 = Math.sin(cycles * TWO_PI2) * 0.05 * gait;
|
|
8804
9117
|
if (!itemUse) {
|
|
8805
|
-
return { armL: -0.45 +
|
|
9118
|
+
return { armL: -0.45 + bob2, armLz: 0.22, elbL: -1.05 };
|
|
8806
9119
|
}
|
|
8807
9120
|
const { id, position, rotation } = itemUse;
|
|
8808
9121
|
if (id === "drink" || id === "sip" || id === "chug") {
|
|
@@ -8815,7 +9128,7 @@ var GameCharactersThree = (() => {
|
|
|
8815
9128
|
headX: -0.26 * tilt3
|
|
8816
9129
|
};
|
|
8817
9130
|
}
|
|
8818
|
-
if (id === "open" || id === "close") {
|
|
9131
|
+
if (id === "open" || id === "close" || itemUse.gripL !== void 0) {
|
|
8819
9132
|
const reach = clamp((0.22 - position[0]) / 0.12, 0, 1);
|
|
8820
9133
|
return {
|
|
8821
9134
|
armL: -0.45 - 0.35 * reach,
|
|
@@ -8914,6 +9227,31 @@ var GameCharactersThree = (() => {
|
|
|
8914
9227
|
drop: Math.abs(Math.sin(ph)) * WALK_BOB * gait
|
|
8915
9228
|
};
|
|
8916
9229
|
};
|
|
9230
|
+
const sitPose = (hip) => {
|
|
9231
|
+
const knee = hip - legLengths.hipBelowTrunk - legLengths.thigh * Math.cos(SIT.thigh);
|
|
9232
|
+
const shinFromVertical = Math.acos(clamp(knee / legLengths.shin, 0, 1));
|
|
9233
|
+
const bend = -SIT.thigh - shinFromVertical;
|
|
9234
|
+
return {
|
|
9235
|
+
legL: SIT.thigh,
|
|
9236
|
+
legR: SIT.thigh,
|
|
9237
|
+
kneeL: bend,
|
|
9238
|
+
kneeR: bend,
|
|
9239
|
+
lean: SIT.lean,
|
|
9240
|
+
drop: hip - HIP_HEIGHT,
|
|
9241
|
+
armR: SIT.arm,
|
|
9242
|
+
armL: SIT.arm,
|
|
9243
|
+
armRz: SIT.armZ,
|
|
9244
|
+
armLz: -SIT.armZ,
|
|
9245
|
+
elbR: SIT.elbow,
|
|
9246
|
+
elbL: SIT.elbow
|
|
9247
|
+
};
|
|
9248
|
+
};
|
|
9249
|
+
const liePose = () => ({ legL: 0, legR: 0, kneeL: LIE.knee, kneeR: LIE.knee, lean: 0, drop: 0, armR: 0, armL: 0, armRz: LIE.armZ, armLz: -LIE.armZ, elbR: LIE.elbow, elbL: LIE.elbow });
|
|
9250
|
+
const layBody = (hip) => {
|
|
9251
|
+
tilt.rotation.set(-Math.PI / 2, 0, 0, "XYZ");
|
|
9252
|
+
const pivot = new THREE.Vector3(0, HIP_HEIGHT, 0).applyEuler(tilt.rotation);
|
|
9253
|
+
tilt.position.set(0, hip, 0).sub(pivot);
|
|
9254
|
+
};
|
|
8917
9255
|
const placeBody = (progress) => {
|
|
8918
9256
|
const fk = progress * progress * (3 - 2 * progress);
|
|
8919
9257
|
const flip = fract(cycles * 1.7) >= 0.5 ? 1 : 0;
|
|
@@ -8963,6 +9301,7 @@ var GameCharactersThree = (() => {
|
|
|
8963
9301
|
return run ? run.clip.id : null;
|
|
8964
9302
|
},
|
|
8965
9303
|
update(dt, state = {}) {
|
|
9304
|
+
armReach.restore();
|
|
8966
9305
|
const speed = state.speed ?? 0;
|
|
8967
9306
|
const moving = speed >= 0.05;
|
|
8968
9307
|
const down = !!state.down;
|
|
@@ -8973,13 +9312,27 @@ var GameCharactersThree = (() => {
|
|
|
8973
9312
|
profile.bob = (running ? RUN_BOB : WALK_BOB) * gait;
|
|
8974
9313
|
time = cycles / (walkCadence(Math.max(speed, 0)) * (running ? 1.3 : 1));
|
|
8975
9314
|
animator.animate(body, time, { speed });
|
|
9315
|
+
bob = rig.fig.position.y - rig.dropBase;
|
|
8976
9316
|
fall = fallSeconds <= 0 ? down ? 1 : 0 : clamp(fall + (down ? dt : -dt) / fallSeconds, 0, 1);
|
|
8977
9317
|
resetLegYaw();
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
9318
|
+
const seat = down ? null : state.seat ?? null;
|
|
9319
|
+
if (down) {
|
|
9320
|
+
animator.setPose(rig, downPose());
|
|
9321
|
+
bob = rig.fig.position.y - rig.dropBase;
|
|
9322
|
+
} else if (seat) {
|
|
9323
|
+
animator.setPose(rig, seat.pose === "lie" ? liePose() : sitPose(seat.hip));
|
|
9324
|
+
bob = 0;
|
|
9325
|
+
} else {
|
|
9326
|
+
if (running) {
|
|
9327
|
+
animator.setPose(rig, runningPose(gait, Boolean(state.armed || state.holding || state.itemUse)));
|
|
9328
|
+
bob = rig.fig.position.y - rig.dropBase;
|
|
9329
|
+
}
|
|
9330
|
+
if (state.crouch) {
|
|
9331
|
+
animator.setPose(rig, crouchPose(gait));
|
|
9332
|
+
bob = rig.fig.position.y - rig.dropBase - CROUCH.drop;
|
|
9333
|
+
}
|
|
8982
9334
|
if (state.push) animator.setPose(rig, pushingPose(state.push));
|
|
9335
|
+
else if (state.door) animator.setPose(rig, doorPose(state.door));
|
|
8983
9336
|
else if (state.armed) animator.setPose(rig, armed(state.pitch ?? 0, gait, state.hip ?? 0));
|
|
8984
9337
|
else if (state.holding || state.itemUse) animator.setPose(rig, holdingPose(gait, state.itemUse));
|
|
8985
9338
|
else if (!running) {
|
|
@@ -8991,20 +9344,33 @@ var GameCharactersThree = (() => {
|
|
|
8991
9344
|
});
|
|
8992
9345
|
}
|
|
8993
9346
|
}
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
9347
|
+
if (seat?.pose === "lie") layBody(seat.hip);
|
|
9348
|
+
else placeBody(fall);
|
|
9349
|
+
stepClip(dt, down, Boolean(state.crouch || seat));
|
|
9350
|
+
const cascadeDt = run && !run.clip.loop ? dt * clipCascade : dt;
|
|
9351
|
+
const targetWithoutBob = rig.fig.position.y - bob;
|
|
9352
|
+
if (smooth) animator.cascade(rig, cascadeDt);
|
|
9353
|
+
hipWithoutBob = smooth && hipWithoutBob !== null ? stepCascade(hipWithoutBob, targetWithoutBob, cascadeDt, "hip") : targetWithoutBob;
|
|
9354
|
+
bob = rig.fig.position.y - hipWithoutBob;
|
|
8997
9355
|
const blow = run?.clip.events?.find((event) => (event.type === "impact" || event.type === "grip") && event.data?.kind)?.data?.kind;
|
|
8998
9356
|
const ph = cycles * TWO_PI2;
|
|
8999
9357
|
hands.forEach((hand) => {
|
|
9000
9358
|
const isRight = hand.side < 0;
|
|
9001
9359
|
const holdRight = isRight && (!!state.holding || !!state.itemUse);
|
|
9002
|
-
const holdLeft = !isRight && (state.itemUse?.id === "open" || state.itemUse?.id === "close");
|
|
9003
|
-
const grip = blow === "punch" ? 1.4 : blow === "shove" ? 0.15 : state.armed || holdRight || holdLeft ? 1.22 : running ? 0.85 : 0.12;
|
|
9360
|
+
const holdLeft = !isRight && (state.itemUse?.id === "open" || state.itemUse?.id === "close" || state.itemUse?.gripL !== void 0);
|
|
9361
|
+
const grip = !isRight && state.itemUse?.gripL !== void 0 ? 1.22 * state.itemUse.gripL : blow === "punch" ? 1.4 : blow === "shove" ? 0.15 : state.armed || holdRight || holdLeft ? 1.22 : running ? 0.85 : 0.12;
|
|
9004
9362
|
const wristSwing = holdRight || state.armed || running ? 0 : -Math.min(1, gait) * Math.sin(ph - 0.6) * 0.12 * hand.side;
|
|
9005
9363
|
setHandGrip(hand, grip, wristSwing);
|
|
9006
9364
|
});
|
|
9365
|
+
root.updateMatrixWorld(true);
|
|
9366
|
+
root.worldToLocal(eyeSocket.getWorldPosition(eyeLocal));
|
|
9367
|
+
eyeLocal.y -= (1 - eyeBob) * bob;
|
|
9368
|
+
},
|
|
9369
|
+
eye(out = new THREE.Vector3()) {
|
|
9370
|
+
root.updateWorldMatrix(true, false);
|
|
9371
|
+
return root.localToWorld(out.copy(eyeLocal));
|
|
9007
9372
|
},
|
|
9373
|
+
setView: (mode, camera) => headHider.setView(mode, camera),
|
|
9008
9374
|
play(clip, playOptions = {}) {
|
|
9009
9375
|
const found = typeof clip === "string" ? clips.get(clip) : clip;
|
|
9010
9376
|
if (!found) throw new Error(`Unknown pose clip: ${String(clip)}`);
|
|
@@ -9016,6 +9382,12 @@ var GameCharactersThree = (() => {
|
|
|
9016
9382
|
if (run) run.target = 0;
|
|
9017
9383
|
},
|
|
9018
9384
|
hand: (side) => sockets[side],
|
|
9385
|
+
shoulder: (side) => armOf[side].g,
|
|
9386
|
+
reach(targets, view) {
|
|
9387
|
+
if (run || fall > 0) return;
|
|
9388
|
+
root.updateMatrixWorld(true);
|
|
9389
|
+
armReach.apply(targets, view);
|
|
9390
|
+
},
|
|
9019
9391
|
on(_type, listener) {
|
|
9020
9392
|
listeners.add(listener);
|
|
9021
9393
|
return () => void listeners.delete(listener);
|
|
@@ -9446,7 +9818,9 @@ var GameCharactersThree = (() => {
|
|
|
9446
9818
|
shoulder: [0.16, -0.36, 0.18],
|
|
9447
9819
|
upper: 0.32,
|
|
9448
9820
|
fore: 0.3,
|
|
9449
|
-
reachShift: 0.
|
|
9821
|
+
reachShift: 0.42,
|
|
9822
|
+
reachBend: [1.35, 0.95],
|
|
9823
|
+
elbowView: [[0.96, -0.26, -0.06], null],
|
|
9450
9824
|
wrist: 0.07,
|
|
9451
9825
|
elbowPole: [0.45, -1, 0.2],
|
|
9452
9826
|
shoulderLeft: [-0.07, -0.46, 0.18],
|
|
@@ -9473,22 +9847,14 @@ var GameCharactersThree = (() => {
|
|
|
9473
9847
|
};
|
|
9474
9848
|
|
|
9475
9849
|
// src/first-person/hand.ts
|
|
9476
|
-
var
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
{ z: 9e-3, lengths: [0.035, 0.025, 0.02], width: 0.0155 },
|
|
9480
|
-
{ z: 0.027, lengths: [0.029, 0.02, 0.018], width: 0.0135 }
|
|
9481
|
-
];
|
|
9482
|
-
var PALM = { length: 0.09, thick: 0.026, width: 0.09, wristWidth: 0.066 };
|
|
9483
|
-
var FINGER_THICK = 0.0135;
|
|
9484
|
-
var CURL = { near: 1.05, mid: 1.25, far: 0.85, spread: 0.06 };
|
|
9485
|
-
var THUMB = { base: [5e-3, -6e-3, -0.044], near: 0.034, far: 0.028, width: 0.019 };
|
|
9850
|
+
var PALM = { radius: 0.048, scale: [0.6, 1.05, 1], down: 0.035 };
|
|
9851
|
+
var CURL = { closed: 1.25, near: 0.9, far: 1.1 };
|
|
9852
|
+
var THUMB = { open: 0.32, closed: 0.25 };
|
|
9486
9853
|
var createHandMesh = (THREE, skin, wristSkin = skin) => {
|
|
9487
9854
|
const root = new THREE.Group();
|
|
9488
9855
|
root.name = "first-person-hand";
|
|
9489
9856
|
const geometries = [];
|
|
9490
|
-
const
|
|
9491
|
-
const geometry = new THREE.BoxGeometry(sx, sy, sz);
|
|
9857
|
+
const add = (parent, geometry, material, x = 0, y = 0, z = 0) => {
|
|
9492
9858
|
geometries.push(geometry);
|
|
9493
9859
|
const mesh2 = new THREE.Mesh(geometry, material);
|
|
9494
9860
|
mesh2.position.set(x, y, z);
|
|
@@ -9496,64 +9862,26 @@ var GameCharactersThree = (() => {
|
|
|
9496
9862
|
parent.add(mesh2);
|
|
9497
9863
|
return mesh2;
|
|
9498
9864
|
};
|
|
9499
|
-
const
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
|
|
9505
|
-
|
|
9506
|
-
const palm = new THREE.Mesh(palmGeometry, skin);
|
|
9507
|
-
palm.frustumCulled = false;
|
|
9508
|
-
root.add(palm);
|
|
9509
|
-
const wristGeometry = new THREE.CylinderGeometry(0.03, 0.033, 0.05, 8);
|
|
9865
|
+
const group = new THREE.Group();
|
|
9866
|
+
group.quaternion.setFromRotationMatrix(new THREE.Matrix4().makeBasis(new THREE.Vector3(0, -1, 0), new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 0, -1)));
|
|
9867
|
+
group.position.set(-PALM.down, 0, 0);
|
|
9868
|
+
root.add(group);
|
|
9869
|
+
add(group, new THREE.SphereGeometry(PALM.radius, 14, 10), skin, 0, -PALM.down, 0).scale.set(...PALM.scale);
|
|
9870
|
+
const built = buildHand({ THREE, add, hg: group, handM: skin, s: -1, detailed: true });
|
|
9871
|
+
const wristGeometry = new THREE.CylinderGeometry(0.03, 0.033, 0.05, 10);
|
|
9510
9872
|
wristGeometry.rotateZ(Math.PI / 2);
|
|
9511
|
-
|
|
9512
|
-
const wrist = new THREE.Mesh(wristGeometry, wristSkin);
|
|
9513
|
-
wrist.position.set(-PALM.length / 2 - 0.018, 0, 0);
|
|
9514
|
-
wrist.frustumCulled = false;
|
|
9515
|
-
root.add(wrist);
|
|
9516
|
-
const joints = [];
|
|
9517
|
-
FINGERS.forEach((finger, index) => {
|
|
9518
|
-
const segments = [];
|
|
9519
|
-
let parent = root;
|
|
9520
|
-
let at = PALM.length / 2;
|
|
9521
|
-
finger.lengths.forEach((length, k) => {
|
|
9522
|
-
const group = new THREE.Group();
|
|
9523
|
-
group.position.set(at, k === 0 ? 2e-3 : 0, k === 0 ? finger.z : 0);
|
|
9524
|
-
const taper = 1 - k * 0.07;
|
|
9525
|
-
box2(group, length, FINGER_THICK * taper, finger.width * taper, length / 2, 0, 0);
|
|
9526
|
-
parent.add(group);
|
|
9527
|
-
segments.push(group);
|
|
9528
|
-
parent = group;
|
|
9529
|
-
at = length;
|
|
9530
|
-
});
|
|
9531
|
-
joints.push({ segments, weight: 1 + index * (CURL.spread / CURL.near) });
|
|
9532
|
-
});
|
|
9533
|
-
const thumbNear = new THREE.Group();
|
|
9534
|
-
thumbNear.rotation.order = "YZX";
|
|
9535
|
-
thumbNear.position.set(...THUMB.base);
|
|
9536
|
-
box2(thumbNear, THUMB.near, FINGER_THICK * 1.1, THUMB.width, THUMB.near / 2, 0, 0);
|
|
9537
|
-
const thumbFar = new THREE.Group();
|
|
9538
|
-
thumbFar.position.set(THUMB.near, 0, 0);
|
|
9539
|
-
box2(thumbFar, THUMB.far, FINGER_THICK, THUMB.width * 0.9, THUMB.far / 2, 0, 0);
|
|
9540
|
-
thumbNear.add(thumbFar);
|
|
9541
|
-
root.add(thumbNear);
|
|
9873
|
+
add(root, wristGeometry, wristSkin, -PALM.down - 0.03, 0, 0);
|
|
9542
9874
|
let lastGrip = 0;
|
|
9543
9875
|
let indexCurl;
|
|
9544
|
-
const
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
if (!finger) return;
|
|
9548
|
-
const k = indexCurl === void 0 ? lastGrip : Math.min(1, Math.max(0, indexCurl));
|
|
9549
|
-
finger.segments.forEach((segment, i) => segment.rotation.z = -curl[i] * k * finger.weight);
|
|
9876
|
+
const curlFinger = (finger, k) => {
|
|
9877
|
+
built.fingers[finger * 2].rotation.z = k * CURL.closed * CURL.near;
|
|
9878
|
+
built.fingers[finger * 2 + 1].rotation.z = k * CURL.closed * CURL.far;
|
|
9550
9879
|
};
|
|
9880
|
+
const applyIndex = () => curlFinger(0, indexCurl === void 0 ? lastGrip : Math.min(1, Math.max(0, indexCurl)));
|
|
9551
9881
|
const setGrip = (grip) => {
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
thumbNear.rotation.set(0, 0.55 - 1.45 * k, -0.1 - 0.75 * k);
|
|
9556
|
-
thumbFar.rotation.z = -0.1 - 0.7 * k;
|
|
9882
|
+
lastGrip = Math.min(1, Math.max(0, grip));
|
|
9883
|
+
for (let finger = 1; finger < 4; finger++) curlFinger(finger, lastGrip);
|
|
9884
|
+
if (built.th) built.th.rotation.z = THUMB.open + lastGrip * THUMB.closed;
|
|
9557
9885
|
applyIndex();
|
|
9558
9886
|
};
|
|
9559
9887
|
const setIndex = (value) => {
|
|
@@ -9571,33 +9899,12 @@ var GameCharactersThree = (() => {
|
|
|
9571
9899
|
};
|
|
9572
9900
|
};
|
|
9573
9901
|
|
|
9574
|
-
// src/first-person/ik.ts
|
|
9575
|
-
var solveTwoBone = (root, target, upper, lower, pole, out) => {
|
|
9576
|
-
const line = out.line.copy(target).sub(root);
|
|
9577
|
-
let distance3 = line.length();
|
|
9578
|
-
if (distance3 < 1e-6) line.set(0, 0, -1);
|
|
9579
|
-
else line.divideScalar(distance3);
|
|
9580
|
-
const min = Math.abs(upper - lower) + 1e-4;
|
|
9581
|
-
const max = upper + lower - 1e-4;
|
|
9582
|
-
out.clamped = distance3 > max || distance3 < min;
|
|
9583
|
-
distance3 = Math.min(max, Math.max(min, distance3));
|
|
9584
|
-
const along = (distance3 * distance3 + upper * upper - lower * lower) / (2 * distance3);
|
|
9585
|
-
const across = Math.sqrt(Math.max(0, upper * upper - along * along));
|
|
9586
|
-
const side = out.side.copy(pole);
|
|
9587
|
-
side.addScaledVector(line, -side.dot(line));
|
|
9588
|
-
if (side.lengthSq() < 1e-8) side.set(0, 1, 0).addScaledVector(line, -line.y);
|
|
9589
|
-
if (side.lengthSq() < 1e-8) side.set(1, 0, 0);
|
|
9590
|
-
side.normalize();
|
|
9591
|
-
out.joint.copy(root).addScaledVector(line, along).addScaledVector(side, across);
|
|
9592
|
-
out.end.copy(root).addScaledVector(line, distance3);
|
|
9593
|
-
return out;
|
|
9594
|
-
};
|
|
9595
|
-
var createTwoBone = (THREE) => ({ joint: new THREE.Vector3(), end: new THREE.Vector3(), clamped: false, line: new THREE.Vector3(), side: new THREE.Vector3() });
|
|
9596
|
-
|
|
9597
9902
|
// src/first-person/arms.ts
|
|
9598
9903
|
var DEFAULT_BLEND = 0.18;
|
|
9599
9904
|
var ELBOW_SEGMENTS = 8;
|
|
9600
9905
|
var REACH_SLACK = 0.97;
|
|
9906
|
+
var ELBOW_VIEW_MARGIN = 0.86;
|
|
9907
|
+
var ELBOW_VIEW_PASSES = 4;
|
|
9601
9908
|
var CONTACT_PROBE = 1.4;
|
|
9602
9909
|
var CONTACT_MIN = 0.12;
|
|
9603
9910
|
var CONTACT_MARGIN = 5e-3;
|
|
@@ -9746,6 +10053,11 @@ var GameCharactersThree = (() => {
|
|
|
9746
10053
|
const shoulderOf = (sign2, out) => sign2 === -1 && rig.shoulderLeft ? out.set(...rig.shoulderLeft) : out.set(rig.shoulder[0] * sign2, rig.shoulder[1], rig.shoulder[2]);
|
|
9747
10054
|
const poleOf = (sign2) => sign2 === -1 && rig.elbowPoleLeft ? new THREE.Vector3(...rig.elbowPoleLeft) : new THREE.Vector3(rig.elbowPole[0] * sign2, rig.elbowPole[1], rig.elbowPole[2]);
|
|
9748
10055
|
const kneePole = new THREE.Vector3(...rig.kneePole);
|
|
10056
|
+
const reachOf = (sign2) => {
|
|
10057
|
+
const bend = rig.reachBend?.[sign2 === 1 ? 0 : 1];
|
|
10058
|
+
if (bend === void 0) return (rig.upper + rig.fore) * REACH_SLACK;
|
|
10059
|
+
return Math.sqrt(rig.upper * rig.upper + rig.fore * rig.fore + 2 * rig.upper * rig.fore * Math.cos(bend));
|
|
10060
|
+
};
|
|
9749
10061
|
const hip = new THREE.Vector3(...rig.hip);
|
|
9750
10062
|
const euler = new THREE.Euler(0, 0, 0, "YZX");
|
|
9751
10063
|
const quaternionOf = (r) => new THREE.Quaternion().setFromEuler(euler.set(r[0], r[1], r[2], "YZX"));
|
|
@@ -9835,15 +10147,45 @@ var GameCharactersThree = (() => {
|
|
|
9835
10147
|
out.scale = base.scale;
|
|
9836
10148
|
return out;
|
|
9837
10149
|
};
|
|
9838
|
-
const
|
|
10150
|
+
const elbowAt = new THREE.Vector3();
|
|
10151
|
+
const viewOf = (camera) => {
|
|
10152
|
+
const lens = camera;
|
|
10153
|
+
if (!lens.isPerspectiveCamera) return null;
|
|
10154
|
+
const tanV = Math.tan(lens.fov * Math.PI / 360);
|
|
10155
|
+
return { tanV, tanH: tanV * lens.aspect };
|
|
10156
|
+
};
|
|
10157
|
+
const placeElbowInView = (sign2, view) => {
|
|
10158
|
+
const way = rig.elbowView?.[sign2 === 1 ? 0 : 1];
|
|
10159
|
+
if (!way) return false;
|
|
10160
|
+
elbowAt.set(way[0], way[1], way[2]).setLength(rig.fore).add(wristAt);
|
|
10161
|
+
for (let pass = 0; pass < ELBOW_VIEW_PASSES; pass++) {
|
|
10162
|
+
const depth = Math.max(0.05, -elbowAt.z);
|
|
10163
|
+
const high = view.tanV * ELBOW_VIEW_MARGIN * depth;
|
|
10164
|
+
const wide = view.tanH * ELBOW_VIEW_MARGIN * depth;
|
|
10165
|
+
elbowAt.y = Math.max(elbowAt.y, -high);
|
|
10166
|
+
elbowAt.x = Math.min(wide, Math.max(-wide, elbowAt.x));
|
|
10167
|
+
elbowAt.sub(wristAt).setLength(rig.fore).add(wristAt);
|
|
10168
|
+
}
|
|
10169
|
+
shoulder.sub(elbowAt).setLength(rig.upper).add(elbowAt);
|
|
10170
|
+
return true;
|
|
10171
|
+
};
|
|
10172
|
+
const drawArm = (arm, pose, view) => {
|
|
9839
10173
|
copyPose(arm.drawn, pose);
|
|
9840
10174
|
const scale = pose.scale;
|
|
9841
10175
|
fingers.set(1, 0, 0).applyQuaternion(pose.q);
|
|
9842
10176
|
wristAt.copy(pose.p).addScaledVector(fingers, -rig.wrist * scale);
|
|
9843
10177
|
shoulderOf(arm.sign, shoulder).add(bobOffset);
|
|
9844
|
-
|
|
10178
|
+
if (view && placeElbowInView(arm.sign, view)) {
|
|
10179
|
+
solveTwoBone(shoulder, wristAt, rig.upper, rig.fore, towards.copy(elbowAt).sub(shoulder).add(elbowAt).sub(wristAt), bone);
|
|
10180
|
+
finishArm(arm, pose, scale);
|
|
10181
|
+
return;
|
|
10182
|
+
}
|
|
10183
|
+
const excess = shoulder.distanceTo(wristAt) - reachOf(arm.sign);
|
|
9845
10184
|
if (excess > 0 && rig.reachShift > 0) shoulder.addScaledVector(towards.subVectors(wristAt, shoulder).normalize(), Math.min(excess, rig.reachShift));
|
|
9846
10185
|
solveTwoBone(shoulder, wristAt, rig.upper, rig.fore, poleOf(arm.sign), bone);
|
|
10186
|
+
finishArm(arm, pose, scale);
|
|
10187
|
+
};
|
|
10188
|
+
const finishArm = (arm, pose, scale) => {
|
|
9847
10189
|
palmAt.copy(bone.end).addScaledVector(fingers, rig.wrist * scale);
|
|
9848
10190
|
arm.drawn.p.copy(palmAt);
|
|
9849
10191
|
arm.anchor.position.copy(palmAt);
|
|
@@ -9955,7 +10297,7 @@ var GameCharactersThree = (() => {
|
|
|
9955
10297
|
dropped.p.y -= AWAY_DROP * ease2(arm.away);
|
|
9956
10298
|
pose = dropped;
|
|
9957
10299
|
}
|
|
9958
|
-
drawArm(arm, pose);
|
|
10300
|
+
drawArm(arm, pose, mode === "target" && targets?.elbows !== "body" ? viewOf(state.camera) : null);
|
|
9959
10301
|
const shown = arm.away < AWAY_HIDDEN;
|
|
9960
10302
|
for (const part of [arm.anchor, arm.upper, arm.fore, arm.cuff, arm.elbow]) part.visible = shown;
|
|
9961
10303
|
}
|
|
@@ -10003,7 +10345,7 @@ var GameCharactersThree = (() => {
|
|
|
10003
10345
|
var isPunch = (clip) => clip.events?.some((event) => event.type === "impact" && event.data?.kind === "punch") ?? false;
|
|
10004
10346
|
var GUARD_SPEED = 0.3;
|
|
10005
10347
|
var toRoomAvatar = (avatar, options = {}) => {
|
|
10006
|
-
const arms = options.firstPerson === false ? null : createFirstPersonArms(avatar.three, {
|
|
10348
|
+
const arms = options.firstPerson === false || options.firstPerson === void 0 ? null : createFirstPersonArms(avatar.three, {
|
|
10007
10349
|
colors: { skin: avatar.colors.skin, sleeve: avatar.colors.longSleeves ? avatar.colors.shirt : avatar.colors.skin, trouser: avatar.colors.trousers, shoe: avatar.colors.shoes, ...options.firstPerson?.colors },
|
|
10008
10350
|
clips: options.firstPersonClips ?? FIRST_PERSON_CLIPS,
|
|
10009
10351
|
hideWhenIdle: true,
|
|
@@ -10024,7 +10366,7 @@ var GameCharactersThree = (() => {
|
|
|
10024
10366
|
let guarding = false;
|
|
10025
10367
|
const stepGuard = (dt, state) => {
|
|
10026
10368
|
if (!guard) return;
|
|
10027
|
-
const free = state.speed < GUARD_SPEED && !state.down && !state.armed && !state.holding && !state.push && !state.itemUse && !state.running;
|
|
10369
|
+
const free = state.speed < GUARD_SPEED && !state.down && !state.armed && !state.holding && !state.push && !state.door && !state.itemUse && !state.running;
|
|
10028
10370
|
if (strikeLeft > 0) {
|
|
10029
10371
|
strikeLeft -= dt;
|
|
10030
10372
|
if (strikeLeft <= 0 && guardLeft > 0 && free) {
|
|
@@ -10043,7 +10385,8 @@ var GameCharactersThree = (() => {
|
|
|
10043
10385
|
root: avatar.root,
|
|
10044
10386
|
avatar,
|
|
10045
10387
|
arms,
|
|
10046
|
-
|
|
10388
|
+
eye: (out) => avatar.eye(out),
|
|
10389
|
+
setView: (mode, camera) => avatar.setView(mode, camera),
|
|
10047
10390
|
update: (dt, state) => {
|
|
10048
10391
|
stepGuard(dt, state);
|
|
10049
10392
|
avatar.update(dt, {
|
|
@@ -10055,10 +10398,14 @@ var GameCharactersThree = (() => {
|
|
|
10055
10398
|
pitch: -state.pitch,
|
|
10056
10399
|
...state.holding !== void 0 ? { holding: state.holding } : {},
|
|
10057
10400
|
...state.itemUse !== void 0 ? { itemUse: state.itemUse } : {},
|
|
10058
|
-
...state.push !== void 0 ? { push: state.push } : {}
|
|
10401
|
+
...state.push !== void 0 ? { push: state.push } : {},
|
|
10402
|
+
...state.seat !== void 0 ? { seat: state.seat } : {},
|
|
10403
|
+
...state.door !== void 0 ? { door: state.door } : {}
|
|
10059
10404
|
});
|
|
10060
10405
|
},
|
|
10061
10406
|
hand: (side) => avatar.hand(side),
|
|
10407
|
+
shoulder: (side) => avatar.shoulder(side),
|
|
10408
|
+
reach: (targets, view) => avatar.reach(targets, view),
|
|
10062
10409
|
strike: (clipId, strikeOptions) => {
|
|
10063
10410
|
const clip = strikes.get(clipId);
|
|
10064
10411
|
if (!clip) return null;
|