-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(stage-ui): animate idle eye and focus movements on Live2D models (…
…#23)
- Loading branch information
1 parent
61a2848
commit 38ce04f
Showing
6 changed files
with
101 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import type { InternalModel } from 'pixi-live2d-display/cubism4' | ||
|
||
import { lerp, randFloat } from 'three/src/math/MathUtils.js' | ||
|
||
import { randomSaccadeInterval } from '../../utils' | ||
|
||
/** | ||
* This is to simulate idle eye saccades and focus (head) movements in a *pretty* naive way. | ||
* Not using any reactivity here as it's not yet needed. | ||
* Keeping it here as a composable for future extension. | ||
*/ | ||
export function useLive2DIdleEyeFocus() { | ||
let nextSaccadeAfter = -1 | ||
let focusTarget: [number, number] | undefined | ||
let lastSaccadeAt = -1 | ||
|
||
// Function to handle idle eye saccades and focus (head) movements | ||
function update(model: InternalModel, now: number) { | ||
if (now >= nextSaccadeAfter || now < lastSaccadeAt) { | ||
focusTarget = [randFloat(-1, 1), randFloat(-1, 0.7)] | ||
lastSaccadeAt = now | ||
nextSaccadeAfter = now + (randomSaccadeInterval() / 1000) | ||
model.focusController.focus(focusTarget![0] * 0.5, focusTarget![1] * 0.5, false) | ||
} | ||
|
||
model.focusController.update(now - lastSaccadeAt) | ||
const coreModel = model.coreModel as any | ||
// TODO: After emotion mapper, stage editor, eye related parameters should be take cared to be dynamical instead of hardcoding | ||
coreModel.setParameterValueById('ParamEyeBallX', lerp(coreModel.getParameterValueById('ParamEyeBallX'), focusTarget![0], 0.3)) | ||
coreModel.setParameterValueById('ParamEyeBallY', lerp(coreModel.getParameterValueById('ParamEyeBallY'), focusTarget![1], 0.3)) | ||
} | ||
|
||
return { update } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './animation' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
const EYE_SACCADE_INT_STEP = 400 | ||
const EYE_SACCADE_INT_P = [ | ||
[0.075, 800], | ||
[0.110, 0], | ||
[0.125, 0], | ||
[0.140, 0], | ||
[0.125, 0], | ||
[0.050, 0], | ||
[0.040, 0], | ||
[0.030, 0], | ||
[0.020, 0], | ||
[1.000, 0], | ||
] | ||
for (let i = 1; i < EYE_SACCADE_INT_P.length; i++) { | ||
EYE_SACCADE_INT_P[i][0] += EYE_SACCADE_INT_P[i - 1][0] | ||
EYE_SACCADE_INT_P[i][1] = EYE_SACCADE_INT_P[i - 1][1] + EYE_SACCADE_INT_STEP | ||
} | ||
|
||
/** | ||
* This is a simple function to generate a random interval between eye saccades. | ||
* | ||
* @returns Interval in milliseconds | ||
*/ | ||
export function randomSaccadeInterval(): number { | ||
const r = Math.random() | ||
for (let i = 0; i < EYE_SACCADE_INT_P.length; i++) { | ||
if (r <= EYE_SACCADE_INT_P[i][0]) { | ||
return EYE_SACCADE_INT_P[i][1] + Math.random() * EYE_SACCADE_INT_STEP | ||
} | ||
} | ||
return EYE_SACCADE_INT_P[EYE_SACCADE_INT_P.length - 1][1] + Math.random() * EYE_SACCADE_INT_STEP | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from './eye-motions' | ||
export * from './iterator' |