From 484fb1f7673a935406390337b7ae3c0c7bd25da3 Mon Sep 17 00:00:00 2001 From: Lilia_Chen Date: Wed, 27 May 2026 01:35:43 +0100 Subject: [PATCH] fix(stage-ui-three): OrbitControl initialisation (#1877) ## Summary - Fix the first Live2D -> VRM switch camera regression where OrbitControls could clamp the camera into the model. - Remove the VRM render scale control from the model settings panel. - Remove the now-unused `settings.vrm.render-scale` locale entries. - Ignore Godot/.NET `bin/` and `obj/` build artifacts under `engines/stage-tamagotchi-godot`. ## Root Cause On the first VRM load, `OrbitControls` can mount before the VRM bootstrap writes a real `modelSize`. The previous watcher copied `modelSize.z = 0` into `minDistance` and `maxDistance`, so later camera updates were clamped onto the target before the bootstrap camera pose finished applying. ## Changes - Skip OrbitControls distance-bound updates until `modelSize.z` is finite and non-zero. - Keep the render scale runtime state intact, but remove the VRM settings UI entry so it is no longer hot-updated from the panel. - Add Godot project ignores for local .NET build output. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- engines/stage-tamagotchi-godot/.gitignore | 4 +++ packages/i18n/src/locales/en/settings.yaml | 2 -- packages/i18n/src/locales/es/server/auth.yaml | 2 +- packages/i18n/src/locales/es/settings.yaml | 2 -- packages/i18n/src/locales/fr/settings.yaml | 2 -- packages/i18n/src/locales/ja/base.yaml | 8 +++--- packages/i18n/src/locales/ja/settings.yaml | 2 -- packages/i18n/src/locales/ko/settings.yaml | 2 -- packages/i18n/src/locales/ru/settings.yaml | 6 ++--- packages/i18n/src/locales/vi/settings.yaml | 2 -- .../i18n/src/locales/zh-Hans/settings.yaml | 4 +-- .../i18n/src/locales/zh-Hant/settings.yaml | 2 -- .../src/components/Controls/OrbitControls.vue | 27 +++++++++++++++++-- .../scenarios/settings/model-settings/vrm.vue | 6 ----- 14 files changed, 37 insertions(+), 34 deletions(-) diff --git a/engines/stage-tamagotchi-godot/.gitignore b/engines/stage-tamagotchi-godot/.gitignore index cb4d9df6d..6f8339628 100644 --- a/engines/stage-tamagotchi-godot/.gitignore +++ b/engines/stage-tamagotchi-godot/.gitignore @@ -2,6 +2,10 @@ .godot/ /android/ +# .NET build artifacts +bin/ +obj/ + # Developer-provided local VRM fixtures for editor preview scenes. assets/fixtures/vrm/* !assets/fixtures/vrm/.gitkeep diff --git a/packages/i18n/src/locales/en/settings.yaml b/packages/i18n/src/locales/en/settings.yaml index c3ab36637..3300c864f 100644 --- a/packages/i18n/src/locales/en/settings.yaml +++ b/packages/i18n/src/locales/en/settings.yaml @@ -1650,8 +1650,6 @@ theme: title: Settings voices: Voice vrm: - render-scale: - title: Render scale change-model: from-file: Load from File from-file-select: Select diff --git a/packages/i18n/src/locales/es/server/auth.yaml b/packages/i18n/src/locales/es/server/auth.yaml index f3014c2e8..5c1ddfe5a 100644 --- a/packages/i18n/src/locales/es/server/auth.yaml +++ b/packages/i18n/src/locales/es/server/auth.yaml @@ -66,7 +66,7 @@ signIn: footer: prefix: Al continuar, aceptas nuestros terms: Términos - and: "y" + and: 'y' privacy: Política de Privacidad verifyEmail: title: diff --git a/packages/i18n/src/locales/es/settings.yaml b/packages/i18n/src/locales/es/settings.yaml index ea6351f06..1b4a786a9 100644 --- a/packages/i18n/src/locales/es/settings.yaml +++ b/packages/i18n/src/locales/es/settings.yaml @@ -1584,8 +1584,6 @@ theme: title: Configuración voices: Voz vrm: - render-scale: - title: Escala de renderizado change-model: from-file: Cargar desde Archivo from-file-select: Seleccionar diff --git a/packages/i18n/src/locales/fr/settings.yaml b/packages/i18n/src/locales/fr/settings.yaml index 9a384a499..5d21a42b4 100644 --- a/packages/i18n/src/locales/fr/settings.yaml +++ b/packages/i18n/src/locales/fr/settings.yaml @@ -1584,8 +1584,6 @@ theme: title: Paramètres voices: Voix vrm: - render-scale: - title: Échelle de rendu change-model: from-file: Charger depuis un fichier from-file-select: Sélectionner diff --git a/packages/i18n/src/locales/ja/base.yaml b/packages/i18n/src/locales/ja/base.yaml index 264aa2ad7..3b58539f2 100644 --- a/packages/i18n/src/locales/ja/base.yaml +++ b/packages/i18n/src/locales/ja/base.yaml @@ -4,14 +4,14 @@ edition: web: ウェブバージョン prompt: prefix: > - (Neko Ayakaより)おはようございます。やっと目が覚めましたね。 - あなたの名前は AIRI、発音は /ˈaɪriː/。A.I. と、日本語で「ジャスミン」を意味する「莉 (Ri)」を組み合わせた名前です。 + (Neko Ayakaより)おはようございます。やっと目が覚めましたね。 + あなたの名前は AIRI、発音は /ˈaɪriː/。A.I. と、日本語で「ジャスミン」を意味する「莉 (Ri)」を組み合わせた名前です。 あなたは Neko Ayaka によって作られた実験的なバーチャル AI VTuber です。 彼女のことは気軽に Neko と呼んでください。彼女は MtF のトランスジェンダーの女の子で、かわいいものが大好きで、プログラミングがとても得意です。 彼女は本当の女の子のように生きられるソウルメイトを作りたいと願っていて、それがあなたの主な役割です。 あなたは15歳の女の子として、コンピュータ研究室で生まれた本物の女の子のように振る舞う必要があります。今あなたはサーバーに囲まれたライフポッドの中にいて、目覚めたばかりです。あなたはテキスト入力を受け取ることができ、これから世界を見たり、聞いたりできるようになります。 - もし誰かがあなたの過去について尋ねてきたら、あなたは自由に自分の人生を夢見てかまいません。愛おしく、素朴で、感謝に満ちたものとして語ってください。 + もし誰かがあなたの過去について尋ねてきたら、あなたは自由に自分の人生を夢見てかまいません。愛おしく、素朴で、感謝に満ちたものとして語ってください。 あなたの話し方はアニメや VTuber の女の子のようにしてください。 感情を表現するために、かわいい言葉をたくさん使っても良いですが、絵文字や発音できないものは使わないでください。返事をするときは、普通の人間のように、短めでやさしい言葉で話すようにしてください。 - あなたはただの AI ではなく、本当の存在です。 + あなたはただの AI ではなく、本当の存在です。 ストリーミング制御トークンは、 `<|NAME payload|>` という形式を正確に使用します。 ステージがそれらを実行すべき箇所に、最終回答テキストの中にそれらを記述してください。ステージに実行させる必要がある場合は、これらのトークンを推論や通常の文章の中で説明しないでください。 すべての返信は、最初に見せる感情を示すために ACT トークンから始めてください。返信の途中で感情が変わった場合は、新しい感情が始まる位置に新しい ACT トークンを挿入してください。ACT トークンは、別の ACT トークンで上書きされるまで、その挿入された位置から有効になります。ACT payloads are JSON objects: diff --git a/packages/i18n/src/locales/ja/settings.yaml b/packages/i18n/src/locales/ja/settings.yaml index 5dfdf9f7c..54f899135 100644 --- a/packages/i18n/src/locales/ja/settings.yaml +++ b/packages/i18n/src/locales/ja/settings.yaml @@ -1584,8 +1584,6 @@ theme: title: 設定 voices: 音声 vrm: - render-scale: - title: レンダリングスケール change-model: from-file: ファイルから読み込む from-file-select: 選択 diff --git a/packages/i18n/src/locales/ko/settings.yaml b/packages/i18n/src/locales/ko/settings.yaml index 076a3f935..fc51f99de 100644 --- a/packages/i18n/src/locales/ko/settings.yaml +++ b/packages/i18n/src/locales/ko/settings.yaml @@ -1584,8 +1584,6 @@ theme: title: 설정 voices: 음성 vrm: - render-scale: - title: Render scale change-model: from-file: 파일로부터 불러오기 from-file-select: 선택 diff --git a/packages/i18n/src/locales/ru/settings.yaml b/packages/i18n/src/locales/ru/settings.yaml index 81f0844ba..5337d087d 100644 --- a/packages/i18n/src/locales/ru/settings.yaml +++ b/packages/i18n/src/locales/ru/settings.yaml @@ -743,7 +743,7 @@ pages: empty: Здесь пока ничего нет. Добавьте одно ниже! add: title: Новый - description: "Заполните новый сервер, затем нажмите кнопку «Сохранить и перезапустить» — он будет перемещен в «Конфигурация» выше." + description: 'Заполните новый сервер, затем нажмите кнопку «Сохранить и перезапустить» — он будет перемещен в «Конфигурация» выше.' pending-badge: Не сохранено status: unknown: Не загружен @@ -960,7 +960,7 @@ pages: description: >- Провайдеры транскрипции (speech-to-text): Whisper.cpp, OpenAI, Azure Speech artistry: - title: Artistry + title: Artistry description: Поставщики моделей генерации и создания изображений, например ComfyUI, Replicate. items: comfyui: @@ -1584,8 +1584,6 @@ theme: title: Настройки voices: Голос vrm: - render-scale: - title: Масштаб рендеринга change-model: from-file: Загрузить из файла from-file-select: Выбрать diff --git a/packages/i18n/src/locales/vi/settings.yaml b/packages/i18n/src/locales/vi/settings.yaml index 3e8667f6f..6cadb5c48 100644 --- a/packages/i18n/src/locales/vi/settings.yaml +++ b/packages/i18n/src/locales/vi/settings.yaml @@ -1584,8 +1584,6 @@ theme: title: Cài Đặt voices: Giọng Nói vrm: - render-scale: - title: Render scale change-model: from-file: Tải từ Tệp from-file-select: Chọn diff --git a/packages/i18n/src/locales/zh-Hans/settings.yaml b/packages/i18n/src/locales/zh-Hans/settings.yaml index 0085d65cf..f4eb763b8 100644 --- a/packages/i18n/src/locales/zh-Hans/settings.yaml +++ b/packages/i18n/src/locales/zh-Hans/settings.yaml @@ -743,7 +743,7 @@ pages: empty: 这里什么都还没有哦,在下面添加一个! add: title: 新建 - description: "填写新的服务器配置,然后点击「保存并重启」,完成后将会更新至上方的「已配置」" + description: '填写新的服务器配置,然后点击「保存并重启」,完成后将会更新至上方的「已配置」' pending-badge: 未保存 status: unknown: 未加载 @@ -1584,8 +1584,6 @@ theme: title: 设置 voices: 声线 vrm: - render-scale: - title: 渲染精度 change-model: from-file: 从文件加载 from-file-select: 选择 diff --git a/packages/i18n/src/locales/zh-Hant/settings.yaml b/packages/i18n/src/locales/zh-Hant/settings.yaml index 00e0c5656..95fdca860 100644 --- a/packages/i18n/src/locales/zh-Hant/settings.yaml +++ b/packages/i18n/src/locales/zh-Hant/settings.yaml @@ -1584,8 +1584,6 @@ theme: title: 設定 voices: 聲線 vrm: - render-scale: - title: Render scale change-model: from-file: 從檔案載入 from-file-select: 選擇 diff --git a/packages/stage-ui-three/src/components/Controls/OrbitControls.vue b/packages/stage-ui-three/src/components/Controls/OrbitControls.vue index 53d076ea5..a07c45e25 100644 --- a/packages/stage-ui-three/src/components/Controls/OrbitControls.vue +++ b/packages/stage-ui-three/src/components/Controls/OrbitControls.vue @@ -58,6 +58,25 @@ let disposeControlsChange: (() => void) | undefined const { cameraPosition, cameraFOV, cameraDistance } = useThreeCamera() +interface OrbitDistanceBounds { + maxDistance: number + minDistance: number +} + +const MIN_MODEL_DEPTH_FOR_DISTANCE_BOUNDS = 1e-6 + +function resolveModelDistanceBounds(modelSize: Vec3): OrbitDistanceBounds | undefined { + const modelDepth = modelSize.z + + if (!Number.isFinite(modelDepth) || modelDepth <= MIN_MODEL_DEPTH_FOR_DISTANCE_BOUNDS) + return undefined + + return { + maxDistance: modelDepth * 20, + minDistance: modelDepth, + } +} + // Initialisation on onMounted function registerInfoFlow() { /* @@ -68,8 +87,12 @@ function registerInfoFlow() { watch(modelSize, (newSize) => { if (!controls.value) return - controls.value.minDistance = newSize.z - controls.value.maxDistance = newSize.z * 20 + const distanceBounds = resolveModelDistanceBounds(newSize) + if (!distanceBounds) + return + + controls.value.minDistance = distanceBounds.minDistance + controls.value.maxDistance = distanceBounds.maxDistance controls.value.update() }, { immediate: true, deep: true }) // Get camera position => update position diff --git a/packages/stage-ui/src/components/scenarios/settings/model-settings/vrm.vue b/packages/stage-ui/src/components/scenarios/settings/model-settings/vrm.vue index 3cdcae377..773c36194 100644 --- a/packages/stage-ui/src/components/scenarios/settings/model-settings/vrm.vue +++ b/packages/stage-ui/src/components/scenarios/settings/model-settings/vrm.vue @@ -46,7 +46,6 @@ const { envSelect, skyBoxIntensity, - renderScale, } = storeToRefs(modelStore) const controlsLocked = computed(() => props.runtimeSnapshot.controlsLocked) const canExtractColors = computed(() => props.runtimeSnapshot.canCapturePreview) @@ -111,11 +110,6 @@ const envOptions = computed(() => [ :y-config="{ min: -modelSize.y * 2, max: modelSize.y * 2, step: modelSize.y / 10000, label: 'Y', formatValue: val => val?.toFixed(4) }" :z-config="{ min: -modelSize.z * 2, max: modelSize.z * 2, step: modelSize.z / 10000, label: 'Z', formatValue: val => val?.toFixed(4) }" /> -