aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-22 15:06:22 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-22 15:06:22 +0900
commit76cc6003f79df78613b21bd9114dff02874632bf (patch)
treeb4ec4f8df2d44828ef050a84ae71eb66881a0772 /public/bluebey-studio
parentc891299737dd0c73a54f9bd1510dc00d6f140f1f (diff)
bluebey-studio: 口の透過を根本修正し、操作の割り当てを戻す
口は常に深度テストを有効にして体・壁で隠れるようにした。通常ドラッグ=ぶるべー移動、Shift+ドラッグ=視点移動に戻し、ダブルクリック/ボタンで回転中心をぶるべーに合わせられるようにした。
Diffstat (limited to 'public/bluebey-studio')
-rw-r--r--public/bluebey-studio/guide.html5
-rw-r--r--public/bluebey-studio/index.html2
-rw-r--r--public/bluebey-studio/src/main.js50
-rw-r--r--public/bluebey-studio/src/panel.js7
4 files changed, 36 insertions, 28 deletions
diff --git a/public/bluebey-studio/guide.html b/public/bluebey-studio/guide.html
index a6cba9f..73d903d 100644
--- a/public/bluebey-studio/guide.html
+++ b/public/bluebey-studio/guide.html
@@ -110,8 +110,9 @@
</ol>
<h3>パソコンでの操作</h3>
<ul>
- <li>ぶるべーをつかんでドラッグすると、カメラ(見ている基準点)を動かせます。ぶるべーは画面の中心に残ります。</li>
- <li>Shift を押しながらドラッグすると、ぶるべーを移動できます。</li>
+ <li>ぶるべーをつかんでドラッグすると、ぶるべーを移動できます。</li>
+ <li>Shift を押しながらドラッグすると、カメラ(見ている基準点)を動かせます。ぶるべーは画面の中心に残ります。</li>
+ <li>回転の中心をぶるべーに合わせたいときは、ぶるべーをダブルクリックします(「シーン」タブの「画面・光」にある「中心をぶるべーに合わせる」でも同じです)。</li>
<li>向きは、全身とボーンのスライダーや回転ギズモで調整できます。</li>
<li>モデルをクリックすると、その場所に近いボーンが選ばれます。</li>
<li>「元に戻す/やり直す(パネル上部の矢印アイコン)」「すべてをランダムに(?!アイコン)」は、どのタブでも使えます。</li>
diff --git a/public/bluebey-studio/index.html b/public/bluebey-studio/index.html
index 9f2e089..77e527a 100644
--- a/public/bluebey-studio/index.html
+++ b/public/bluebey-studio/index.html
@@ -136,7 +136,7 @@ if (window.matchMedia('(max-width: 768px), (max-height: 500px) and (pointer: coa
<h3>ポーズ</h3>
<ul>
<li>右パネルの「ポーズ」でボーンを選び、X/Y/Zのスライダーを動かします。「ポーズ例」から始めると早いです。</li>
- <li>ぶるべーをつかんでドラッグすると、カメラ(見ている基準点)を動かせます(ぶるべーは中心に残ります)。Shiftを押しながらドラッグすると、ぶるべーを移動できます。</li>
+ <li>ぶるべーをつかんでドラッグすると、ぶるべーを移動できます。Shiftを押しながらドラッグすると、カメラ(見ている基準点)を動かせます(ぶるべーは中心に残ります)。回転の中心をぶるべーに合わせたいときは、ぶるべーをダブルクリックします。</li>
<li>モデルをクリックすると、その場所にいちばん近いボーンが選ばれます。</li>
<li>ギズモ(回転の輪)を直接ドラッグしても回せます。</li>
<li>スライダーの値は「休めの姿勢(レストポーズ)」からの差分です。<code>0,0,0</code> で元の姿勢。</li>
diff --git a/public/bluebey-studio/src/main.js b/public/bluebey-studio/src/main.js
index 6507bf4..d2de72c 100644
--- a/public/bluebey-studio/src/main.js
+++ b/public/bluebey-studio/src/main.js
@@ -1291,11 +1291,22 @@ async function init() {
window.addEventListener('resize', clearOnDesktop);
}
+ /** Put the orbit centre back on ぶるべー (e.g. after moving it off-centre). */
+ function recenterCamera() {
+ const root = state.pose.root ?? [0, 0, 0];
+ state.view.targetX = round2(root[0] ?? 0);
+ state.view.targetY = round2(halfHeight + (root[1] ?? 0));
+ state.view.targetZ = round2(root[2] ?? 0);
+ refresh('view');
+ app.panel?.sync();
+ }
+
Object.assign(app.actions, {
capturePose,
applyState,
refresh,
loadHatModel,
+ recenterCamera,
patch: (scope, value) => applyState({ [scope]: value }, { scope }),
syncPanel: () => app.panel?.sync(),
imageCanvas: (options) => captureImage(options),
@@ -1370,8 +1381,6 @@ async function init() {
const warmupUntil = performance.now() + 2500;
let snotSignature = null;
- const mouthNormal = new THREE.Vector3();
- const mouthToCamera = new THREE.Vector3();
const loop = (now) => {
const rawDelta = now - last;
const dt = Math.min(0.05, rawDelta / 1000);
@@ -1416,29 +1425,14 @@ async function init() {
}
if (face.flush(now, 26)) app.needsRender = true;
- // The mouth artwork normally lets a closed-lip tongue win the depth test so
- // it reads over the 3D nose. That would also draw it through the back of the
- // head and over a 見えない壁, so switch depth testing back on when the camera
- // is behind the face or a wall is in play.
+ // The face artwork used to switch depth testing off so a closed-lip tongue
+ // could draw over the 3D nose. That also let the mouth show through the body
+ // at an angle, so depth testing now always stays on - the tongue still reads
+ // over the nose without it.
const mouthMesh = model.parts.mouthMesh;
- if (mouthMesh?.material) {
- const mouth = state.face.mouth ?? {};
- const tongueOverLip = (mouth.round ?? 0) <= 0.004
- && (mouth.open ?? 0) <= 0.004
- && (mouth.tongue ?? 1) > 0.01;
- mouthMesh.getWorldDirection(mouthNormal);
- mouthMesh.getWorldPosition(mouthToCamera);
- mouthToCamera.subVectors(view.camera.position, mouthToCamera).normalize();
- // Only let the artwork win the depth test when the camera is actually in
- // front of the face. At a side view the dot product is near zero, and the
- // mouth must lose to the body (or it shows through the far side).
- const facing = mouthNormal.dot(mouthToCamera) > 0.5;
- const wallOn = state.render.wall?.on === true || state.render.wall2?.on === true;
- const depthTest = !tongueOverLip || !facing || wallOn;
- if (mouthMesh.material.depthTest !== depthTest) {
- mouthMesh.material.depthTest = depthTest;
- app.needsRender = true;
- }
+ if (mouthMesh?.material && mouthMesh.material.depthTest !== true) {
+ mouthMesh.material.depthTest = true;
+ app.needsRender = true;
}
view.controls.update(dt);
@@ -2386,7 +2380,7 @@ async function init() {
const root = state.pose.root ?? [0, 0, 0];
modelDrag = {
pointerId: event.pointerId,
- pan: event.pointerType === 'mouse' ? !event.shiftKey : false,
+ pan: event.shiftKey,
x: event.clientX,
y: event.clientY,
lastX: event.clientX,
@@ -2465,6 +2459,12 @@ async function init() {
};
canvas.addEventListener('pointerup', endModelDrag);
canvas.addEventListener('pointercancel', endModelDrag);
+
+ canvas.addEventListener('dblclick', (event) => {
+ if (!dragHitAt(event)) return;
+ recenterCamera();
+ toast('回転の中心をぶるべーに合わせました');
+ });
}
function togglePanel() {
diff --git a/public/bluebey-studio/src/panel.js b/public/bluebey-studio/src/panel.js
index 2b405bd..a0b2611 100644
--- a/public/bluebey-studio/src/panel.js
+++ b/public/bluebey-studio/src/panel.js
@@ -2076,6 +2076,13 @@ export function buildPanel(app, root) {
label: '回す速さ', min: 0.2, max: 4, step: 0.1, value: 0.8, format: (v) => v.toFixed(1),
onInput: (v) => { state.view.autoRotateSpeed = v; app.actions.refresh('view'); },
}));
+ cameraSection.add(buttons({
+ items: [{
+ id: 'recenter',
+ label: '中心をぶるべーに合わせる',
+ onClick: () => app.actions.recenterCamera?.(),
+ }],
+ }));
/* ------------------------------------------------------------------ export */