| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- import * as THREE from "three";
- import {
- VRM,
- VRMExpressionManager,
- VRMExpressionPresetName,
- } from "@pixiv/three-vrm";
- import { AutoLookAt } from "./autoLookAt";
- import { AutoBlink } from "./autoBlink";
- import { emotionNames } from "@/features/chat/messages";
- /**
- * Expressionを管理するクラス
- *
- * 主に前の表情を保持しておいて次の表情を適用する際に0に戻す作業や、
- * 前の表情が終わるまで待ってから表情適用する役割を持っている。
- */
- export class ExpressionController {
- private _autoLookAt: AutoLookAt;
- private _autoBlink?: AutoBlink;
- private _expressionManager?: VRMExpressionManager;
- private _currentEmotion: VRMExpressionPresetName | string;
- private _currentLipSync: {
- preset: VRMExpressionPresetName | string;
- value: number;
- } | null;
- constructor(vrm: VRM, camera: THREE.Object3D) {
- this._autoLookAt = new AutoLookAt(vrm, camera);
- this._currentEmotion = "neutral";
- this._currentLipSync = null;
- this.registerExpression(vrm)
- if (vrm.expressionManager) {
- this._expressionManager = vrm.expressionManager;
- this._autoBlink = new AutoBlink(vrm.expressionManager);
- }
- }
- public registerExpression(vrm: VRM) {
- const expressionManager = vrm.expressionManager;
- if (!expressionManager) return;
-
- const { expressionMap: allExpressions, presetExpressionMap: presetExpressions } = expressionManager;
- const oddExpressions = Object.keys(allExpressions).filter(key => !(key in presetExpressions));
-
- oddExpressions.forEach(expressionName => {
- const expression = allExpressions[expressionName];
- if (expression) expressionManager.registerExpression(expression);
- });
- const allExpressionNames = Object.keys(allExpressions);
- emotionNames.push(...allExpressionNames);
- return allExpressionNames;
- }
- public playEmotion(preset: VRMExpressionPresetName | string) {
- const normalizedPreset = `${preset.charAt(0).toUpperCase()}${preset.slice(1)}`;
-
- if (this._currentEmotion == preset) {
- return;
- }
- if (this._currentEmotion != "neutral") {
- this._expressionManager?.setValue(this._currentEmotion, 0);
- }
- if (preset == "neutral") {
- this._autoBlink?.setEnable(true);
- this._currentEmotion = preset;
- return;
- }
- const value = (normalizedPreset in VRMExpressionPresetName) ? (normalizedPreset === "Surprised" ? 0.5 : 1) : 0.5;
- const t = this._autoBlink?.setEnable(false) || 0;
- this._currentEmotion = preset;
- setTimeout(() => {
- this._expressionManager?.setValue(preset, value);
- }, t * 1000);
- }
- public lipSync(preset: VRMExpressionPresetName | string, value: number) {
- if (this._currentLipSync) {
- this._expressionManager?.setValue(this._currentLipSync.preset, 0);
- }
- this._currentLipSync = {
- preset,
- value,
- };
- }
- public update(delta: number) {
- if (this._autoBlink) {
- this._autoBlink.update(delta);
- }
- if (this._currentLipSync) {
- const weight =
- this._currentEmotion === "neutral"
- ? this._currentLipSync.value * 0.5
- : this._currentLipSync.value * 0.25;
- this._expressionManager?.setValue(this._currentLipSync.preset, weight);
- }
- }
- }
|