feat: eye blinking

This commit is contained in:
Neko Ayaka
2024-12-07 03:17:23 +08:00
parent 22395a8c04
commit 289f822669
2 changed files with 51 additions and 1 deletions
+3 -1
View File
@@ -2,7 +2,7 @@
import type { VRMCore } from '@pixiv/three-vrm-core'
import { useLoop, useTresContext } from '@tresjs/core'
import { AnimationMixer } from 'three'
import { clipFromVRMAnimation, loadVRMAnimation } from '~/composables/vrm/animation'
import { clipFromVRMAnimation, loadVRMAnimation, useBlink } from '~/composables/vrm/animation'
import { loadVrm } from '~/composables/vrm/core'
const props = defineProps<{
@@ -21,6 +21,7 @@ const vrm = ref<VRMCore>()
const vrmAnimationMixer = ref<AnimationMixer>()
const { scene } = useTresContext()
const { onBeforeRender } = useLoop()
const blink = useBlink()
watch(() => props.position, ([x, y, z]) => {
if (vrm.value) {
@@ -59,6 +60,7 @@ onMounted(async () => {
onBeforeRender(({ delta }) => {
vrmAnimationMixer.value?.update(delta)
vrm.value?.update(delta)
blink.update(vrm.value, delta)
})
vrm.value = _vrm
@@ -38,3 +38,51 @@ export async function clipFromVRMAnimation(vrm?: VRMCore, animation?: VRMAnimati
// create animation clip
return createVRMAnimationClip(animation, vrm)
}
export function useBlink() {
/**
* Eye blinking animation
*/
const isBlinking = ref(false)
const blinkProgress = ref(0)
const timeSinceLastBlink = ref(0)
const BLINK_DURATION = 0.2 // Duration of a single blink in seconds
const MIN_BLINK_INTERVAL = 1 // Minimum time between blinks
const MAX_BLINK_INTERVAL = 6 // Maximum time between blinks
const nextBlinkTime = ref(Math.random() * (MAX_BLINK_INTERVAL - MIN_BLINK_INTERVAL) + MIN_BLINK_INTERVAL)
// Function to handle blinking animation
function update(vrm: VRMCore | undefined, delta: number) {
if (!vrm?.expressionManager)
return
timeSinceLastBlink.value += delta
// Check if it's time for next blink
if (!isBlinking.value && timeSinceLastBlink.value >= nextBlinkTime.value) {
isBlinking.value = true
blinkProgress.value = 0
}
// Handle blinking animation
if (isBlinking.value) {
blinkProgress.value += delta / BLINK_DURATION
// Calculate blink value using sine curve for smooth animation
const blinkValue = Math.sin(Math.PI * blinkProgress.value)
// Apply blink expression
vrm.expressionManager.setValue('blink', blinkValue)
// Reset blink when animation is complete
if (blinkProgress.value >= 1) {
isBlinking.value = false
timeSinceLastBlink.value = 0
vrm.expressionManager.setValue('blink', 0) // Reset blink value to 0
nextBlinkTime.value = Math.random() * (MAX_BLINK_INTERVAL - MIN_BLINK_INTERVAL) + MIN_BLINK_INTERVAL
}
}
}
return { update }
}