feat: add live2d rendering resolution scaling slider

This commit is contained in:
Rin 2026-04-03 01:32:34 +08:00
parent 4c9564f4b9
commit 27dad69041
8 changed files with 49 additions and 2 deletions

View file

@ -127,6 +127,9 @@ live2d:
description: Limit rendering frame rate
options:
unlimited:
resolution-scaling:
title: Rendering Resolution Scale
description: Adjust Live2D render resolution scaling (base 2x)
microphone: Microphone
models: Model
pages:

View file

@ -120,6 +120,9 @@ live2d:
description: 限制渲染帧率
options:
unlimited: '∞'
resolution-scaling:
title: 渲染分辨率缩放
description: 调整 Live2D 渲染分辨率缩放(基础为 2x
microphone: 麦克风
models: 模型
pages:

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { Screen } from '@proj-airi/ui'
import { storeToRefs } from 'pinia'
import { ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
import Live2DCanvas from './live2d/Canvas.vue'
import Live2DModel from './live2d/Model.vue'
@ -28,6 +28,7 @@ withDefaults(defineProps<{
live2dExpressionEnabled?: boolean
live2dShadowEnabled?: boolean
live2dMaxFps?: number
live2dResolutionScaling?: number
}>(), {
paused: false,
focusAt: () => ({ x: 0, y: 0 }),
@ -41,6 +42,7 @@ withDefaults(defineProps<{
live2dExpressionEnabled: true,
live2dShadowEnabled: true,
live2dMaxFps: 0,
live2dResolutionScaling: 1,
})
const componentState = defineModel<'pending' | 'loading' | 'mounted'>('state', { default: 'pending' })
@ -51,6 +53,7 @@ const live2dCanvasRef = ref<InstanceType<typeof Live2DCanvas>>()
const live2d = useLive2d()
const { position } = storeToRefs(live2d)
const live2dCanvasResolution = computed(() => Math.max(0.5, props.live2dResolutionScaling) * 2)
watch([componentStateModel, componentStateCanvas], () => {
componentState.value = (componentStateModel.value === 'mounted' && componentStateCanvas.value === 'mounted')
@ -73,7 +76,7 @@ defineExpose({
v-model:state="componentStateCanvas"
:width="width"
:height="height"
:resolution="2"
:resolution="live2dCanvasResolution"
:max-fps="live2dMaxFps"
max-h="100dvh"
>

View file

@ -34,6 +34,7 @@ const {
live2dExpressionEnabled,
live2dShadowEnabled,
live2dMaxFps,
live2dResolutionScaling,
} = storeToRefs(settings)
const live2d = useLive2d()
@ -338,6 +339,35 @@ function handleMotionSelect(selectedMotionPath: string | number | undefined) {
</div>
</label>
<FieldRange
v-model="live2dResolutionScaling"
as="div"
:min="0.5"
:max="2"
:step="0.05"
:label="t('settings.live2d.resolution-scaling.title')"
>
<template #label>
<div class="flex items-center justify-between gap-2">
<div class="flex-1">
<div class="text-sm font-medium">
{{ t('settings.live2d.resolution-scaling.title') }}
</div>
<div class="text-xs text-neutral-500 dark:text-neutral-400">
{{ t('settings.live2d.resolution-scaling.description') }}
</div>
</div>
<button
class="px-2 text-xs outline-none"
title="Reset value to default"
@click="() => live2dResolutionScaling = 1"
>
<div class="i-solar:forward-linear transform-scale-x--100 text-neutral-500 dark:text-neutral-400" />
</button>
</div>
</template>
</FieldRange>
<div mt-4 flex items-center justify-between>
<span text-sm text-neutral-600 dark:text-neutral-400>Auto Blink</span>
<Checkbox v-model="live2dAutoBlinkEnabled" />

View file

@ -43,6 +43,7 @@ const {
live2dForceAutoBlinkEnabled,
live2dShadowEnabled,
live2dMaxFps,
live2dResolutionScaling,
} = storeToRefs(settingsStore)
const { scale: live2dScale } = storeToRefs(live2dStore)
const { sceneMutationLocked, scenePhase } = storeToRefs(modelStore)
@ -136,6 +137,7 @@ defineExpose({
:live2d-force-auto-blink-enabled="live2dForceAutoBlinkEnabled"
:live2d-shadow-enabled="live2dShadowEnabled"
:live2d-max-fps="live2dMaxFps"
:live2d-resolution-scaling="live2dResolutionScaling"
/>
</div>
</template>

View file

@ -68,6 +68,7 @@ const {
live2dExpressionEnabled,
live2dShadowEnabled,
live2dMaxFps,
live2dResolutionScaling,
} = storeToRefs(settingsStore)
const { mouthOpenSize } = storeToRefs(useSpeakingStore())
const { audioContext } = useAudioContext()
@ -588,6 +589,7 @@ defineExpose({
:live2d-expression-enabled="live2dExpressionEnabled"
:live2d-shadow-enabled="live2dShadowEnabled"
:live2d-max-fps="live2dMaxFps"
:live2d-resolution-scaling="live2dResolutionScaling"
/>
<ThreeScene
v-if="stageModelRenderer === 'vrm' && showStage"

View file

@ -74,6 +74,7 @@ export const useSettings = defineStore('settings', () => {
live2dExpressionEnabled: live2dRefs.live2dExpressionEnabled,
live2dShadowEnabled: live2dRefs.live2dShadowEnabled,
live2dMaxFps: live2dRefs.live2dMaxFps,
live2dResolutionScaling: live2dRefs.live2dResolutionScaling,
// Theme settings
themeColorsHue: themeRefs.themeColorsHue,

View file

@ -27,6 +27,7 @@ export const useSettingsLive2d = defineStore('settings-live2d', () => {
const live2dExpressionEnabled = useLocalStorageManualReset<boolean>('settings/live2d/expression-enabled', false)
const live2dShadowEnabled = useLocalStorageManualReset<boolean>('settings/live2d/shadow-enabled', true)
const live2dMaxFps = useLocalStorageManualReset<number>('settings/live2d/max-fps', 0)
const live2dResolutionScaling = useLocalStorageManualReset<number>('settings/live2d/resolution-scaling', 1)
function resetState() {
live2dDisableFocus.reset()
@ -36,6 +37,7 @@ export const useSettingsLive2d = defineStore('settings-live2d', () => {
live2dExpressionEnabled.reset()
live2dShadowEnabled.reset()
live2dMaxFps.reset()
live2dResolutionScaling.reset()
}
return {
@ -46,6 +48,7 @@ export const useSettingsLive2d = defineStore('settings-live2d', () => {
live2dExpressionEnabled,
live2dShadowEnabled,
live2dMaxFps,
live2dResolutionScaling,
resetState,
}
})