aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-22 14:49:49 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-22 14:49:49 +0900
commit5b2f8b7979d2fb0b8e0f5be175fdc8651e987bdf (patch)
treecb9b7f31afa9dd0afd82aabc1a7114705ba2b413 /public/bluebey-studio/src
parente5d1b6748a5e9d6e8e7650c657b79fc548b7393d (diff)
bluebey-studio: 後ろから口が見える・壁で隠れない問題を修正
口を閉じた舌出しのときだけ深度テストを外していたが、後ろ姿や見えない壁では常に深度テストを有効に戻すようにした。
Diffstat (limited to 'public/bluebey-studio/src')
-rw-r--r--public/bluebey-studio/src/main.js24
1 files changed, 24 insertions, 0 deletions
diff --git a/public/bluebey-studio/src/main.js b/public/bluebey-studio/src/main.js
index b08ea11..bdf5697 100644
--- a/public/bluebey-studio/src/main.js
+++ b/public/bluebey-studio/src/main.js
@@ -1370,6 +1370,8 @@ 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);
@@ -1414,6 +1416,28 @@ 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.
+ 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);
+ const facing = mouthNormal.dot(mouthToCamera) > 0;
+ 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;
+ }
+ }
+
view.controls.update(dt);
const animating = (state.anim.mode ?? 'off') !== 'off'