aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/main.js
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-03 14:56:41 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-03 14:56:41 +0900
commitc6d1df09c66bcfe8388651866d26ed5d05b4d2d2 (patch)
tree8f55d24a31ec22c1c904157e41ba13cdd88ab420 /public/bluebey-studio/src/main.js
parent27483644d7ba9e819dbb5f64844270dd499f45ff (diff)
public/bluebey-studio: 鼻ちょうちんの追従とひげを修正
鼻ちょうちんの位置が、カメラ移動やポーズ変更のあとに飛ぶ問題を修正。位置はボーン局所座標で持ち、スライダーのオフセットは体の向きに追従させた。寝ている動きでは鼻ちょうちんを自動で表示する。 ひげは「猫」に左右の間隔スライダーを追加し、太さを変えずに大きくできるようにした。カイゼルは先をダリ風のカールにした。
Diffstat (limited to 'public/bluebey-studio/src/main.js')
-rw-r--r--public/bluebey-studio/src/main.js30
1 files changed, 22 insertions, 8 deletions
diff --git a/public/bluebey-studio/src/main.js b/public/bluebey-studio/src/main.js
index 1f6ad6e..c7e6501 100644
--- a/public/bluebey-studio/src/main.js
+++ b/public/bluebey-studio/src/main.js
@@ -275,13 +275,15 @@ async function init() {
if (!group) return;
group.visible = snot?.enabled === true;
if (!group.visible) return;
+ // The offsets are applied in the *bone's* frame, along the world axes measured
+ // once at rest, so the bubble travels with the body. Recomputing them against
+ // the live world matrix made it snap back whenever the body had moved.
const k = 0.01; // artwork px -> world units, enough to nudge the bubble
- const target = group.userData.baseWorld.clone().add(new THREE.Vector3(
- (snot.offsetX ?? 0) * k,
- (snot.offsetY ?? 0) * k,
- (snot.offsetZ ?? 0) * k,
- ));
- group.position.copy(group.userData.bone.worldToLocal(target));
+ const { localBase, axes } = group.userData;
+ group.position.copy(localBase)
+ .addScaledVector(axes.x, (snot.offsetX ?? 0) * k)
+ .addScaledVector(axes.y, (snot.offsetY ?? 0) * k)
+ .addScaledVector(axes.z, (snot.offsetZ ?? 0) * k);
group.userData.baseScale = Number.isFinite(snot.size) ? snot.size : 1;
group.scale.setScalar(group.userData.baseScale);
group.userData.material.color.set(snot.color ?? '#dfe8ff');
@@ -326,8 +328,20 @@ async function init() {
group.add(bubble);
const bone = master.bone;
const baseWorld = centre.clone().add(new THREE.Vector3(radius * 1.9, -radius * 0.85, radius * 0.7));
- group.position.copy(bone.worldToLocal(baseWorld.clone()));
- group.userData = { bubble, material, bone, baseWorld, baseScale: 1 };
+ const localBase = bone.worldToLocal(baseWorld.clone());
+ // World-axis directions expressed in the bone's frame, captured at rest: the
+ // sliders keep meaning "right / up / towards the viewer" while the bubble rides
+ // with the body.
+ const boneQuat = new THREE.Quaternion();
+ bone.getWorldQuaternion(boneQuat);
+ const invQuat = boneQuat.clone().invert();
+ const axes = {
+ x: new THREE.Vector3(1, 0, 0).applyQuaternion(invQuat),
+ y: new THREE.Vector3(0, 1, 0).applyQuaternion(invQuat),
+ z: new THREE.Vector3(0, 0, 1).applyQuaternion(invQuat),
+ };
+ group.position.copy(localBase);
+ group.userData = { bubble, material, bone, localBase, axes, baseScale: 1 };
group.visible = false;
bone.add(group);
return group;