init
This commit is contained in:
247
examples/3d/expressionLibrary.js
Normal file
247
examples/3d/expressionLibrary.js
Normal file
@ -0,0 +1,247 @@
|
||||
// 表情库系统
|
||||
const ExpressionLibrary = {
|
||||
expressions: {
|
||||
// 原有表情
|
||||
smile: {
|
||||
name: '微笑',
|
||||
blendShapes: {
|
||||
mouthsmileleft: 0.4,
|
||||
mouthsmileright: 0.4
|
||||
},
|
||||
duration: 2000
|
||||
},
|
||||
|
||||
disgust: {
|
||||
name: '嫌弃',
|
||||
blendShapes: {
|
||||
mouthupperupright: 0.43,
|
||||
browdownleft: 1,
|
||||
browdownright: 1,
|
||||
nosesneerleft: 1,
|
||||
nosesneerright: 1
|
||||
},
|
||||
duration: 2500
|
||||
},
|
||||
|
||||
smirk: {
|
||||
name: '冷笑',
|
||||
blendShapes: {
|
||||
eyeblinkleft: 0.41,
|
||||
eyeblinkright: 0.41,
|
||||
mouthsmileleft: 0.3
|
||||
},
|
||||
duration: 2000
|
||||
},
|
||||
|
||||
grit: {
|
||||
name: '咬牙切齿',
|
||||
blendShapes: {
|
||||
mouthrolllower: 0.3,
|
||||
mouthrollupper: 0.44,
|
||||
mouthshruglower: 0.42,
|
||||
mouthshrugupper: 0.44,
|
||||
browdownleft: 1,
|
||||
browdownright: 1,
|
||||
nosesneerleft: 1,
|
||||
nosesneerright: 1
|
||||
},
|
||||
duration: 2500
|
||||
},
|
||||
|
||||
// 新增表情
|
||||
surprise: {
|
||||
name: '惊讶',
|
||||
blendShapes: {
|
||||
eyewidenleft: 0.8,
|
||||
eyewidenright: 0.8,
|
||||
browouterupright: 0.7,
|
||||
browouterupleft: 0.7,
|
||||
jawopen: 0.4,
|
||||
mouthfunnel: 0.3
|
||||
},
|
||||
duration: 2000
|
||||
},
|
||||
|
||||
sad: {
|
||||
name: '悲伤',
|
||||
blendShapes: {
|
||||
browinnerup: 0.8,
|
||||
mouthfrownleft: 0.6,
|
||||
mouthfrownright: 0.6,
|
||||
mouthlowerdownleft: 0.4,
|
||||
mouthlowerdownright: 0.4
|
||||
},
|
||||
duration: 3000
|
||||
},
|
||||
|
||||
angry: {
|
||||
name: '生气',
|
||||
blendShapes: {
|
||||
browdownleft: 1,
|
||||
browdownright: 1,
|
||||
eyesquintleft: 0.5,
|
||||
eyesquintright: 0.5,
|
||||
nosesneerleft: 0.7,
|
||||
nosesneerright: 0.7,
|
||||
mouthpressleft: 0.6,
|
||||
mouthpressright: 0.6
|
||||
},
|
||||
duration: 2500
|
||||
},
|
||||
|
||||
thinking: {
|
||||
name: '思考',
|
||||
blendShapes: {
|
||||
eyesquintleft: 0.3,
|
||||
eyesquintright: 0.3,
|
||||
mouthpucker: 0.4,
|
||||
eyelookupleft: 0.3,
|
||||
eyelookupright: 0.3
|
||||
},
|
||||
duration: 3000
|
||||
},
|
||||
|
||||
happy: {
|
||||
name: '开心',
|
||||
blendShapes: {
|
||||
mouthsmileleft: 0.8,
|
||||
mouthsmileright: 0.8,
|
||||
eyesquintleft: 0.4,
|
||||
eyesquintright: 0.4,
|
||||
cheeksquintleft: 0.6,
|
||||
cheeksquintright: 0.6
|
||||
},
|
||||
duration: 2500
|
||||
},
|
||||
|
||||
confused: {
|
||||
name: '困惑',
|
||||
blendShapes: {
|
||||
browouterupleft: 0.6,
|
||||
browdownright: 0.5,
|
||||
mouthfrownleft: 0.3,
|
||||
eyesquintright: 0.3
|
||||
},
|
||||
duration: 2500
|
||||
}
|
||||
},
|
||||
|
||||
// 随机表情播放器
|
||||
randomPlayer: {
|
||||
enabled: false,
|
||||
timeout: null,
|
||||
currentExpression: null,
|
||||
intervalMin: 3000,
|
||||
intervalMax: 8000,
|
||||
|
||||
start: function() {
|
||||
this.enabled = true;
|
||||
this.scheduleNext();
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
this.enabled = false;
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
this.reset();
|
||||
},
|
||||
|
||||
scheduleNext: function() {
|
||||
if (!this.enabled) return;
|
||||
|
||||
const delay = this.intervalMin + Math.random() * (this.intervalMax - this.intervalMin);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.playRandom();
|
||||
}, delay);
|
||||
},
|
||||
|
||||
playRandom: function() {
|
||||
if (!this.enabled) return;
|
||||
|
||||
// 获取启用的表情列表
|
||||
const enabledKeys = window.enabledExpressions && window.enabledExpressions.size > 0
|
||||
? Array.from(window.enabledExpressions)
|
||||
: Object.keys(ExpressionLibrary.expressions);
|
||||
|
||||
if (enabledKeys.length === 0) {
|
||||
this.scheduleNext();
|
||||
return;
|
||||
}
|
||||
|
||||
const randomKey = enabledKeys[Math.floor(Math.random() * enabledKeys.length)];
|
||||
const expression = ExpressionLibrary.expressions[randomKey];
|
||||
|
||||
this.play(expression);
|
||||
},
|
||||
|
||||
play: function(expression) {
|
||||
this.currentExpression = expression;
|
||||
|
||||
// 从主页面获取动画速度参数
|
||||
const speed = window.expressionParams?.speed || 400;
|
||||
|
||||
// 应用表情
|
||||
for (const [name, value] of Object.entries(expression.blendShapes)) {
|
||||
if (window.setIdleAnimation) {
|
||||
window.setIdleAnimation(name, value, speed, 'easeInOutCubic');
|
||||
}
|
||||
}
|
||||
|
||||
// 获取表情的key
|
||||
const expressionKey = Object.keys(ExpressionLibrary.expressions).find(
|
||||
key => ExpressionLibrary.expressions[key] === expression
|
||||
);
|
||||
|
||||
// 使用用户设置的持续时间,如果没有则使用表情默认时间
|
||||
const duration = (window.expressionDurations && window.expressionDurations[expressionKey])
|
||||
|| expression.duration;
|
||||
|
||||
setTimeout(() => {
|
||||
this.reset();
|
||||
this.scheduleNext();
|
||||
}, duration);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
if (!this.currentExpression) return;
|
||||
|
||||
// 从主页面获取参数
|
||||
const speed = window.expressionParams?.speed || 400;
|
||||
|
||||
// 重置表情
|
||||
for (const name of Object.keys(this.currentExpression.blendShapes)) {
|
||||
if (window.setIdleAnimation) {
|
||||
window.setIdleAnimation(name, 0, speed + 100, 'easeInOutCubic');
|
||||
}
|
||||
}
|
||||
|
||||
this.currentExpression = null;
|
||||
}
|
||||
},
|
||||
|
||||
// 手动播放指定表情
|
||||
playExpression: function(expressionName) {
|
||||
const expression = this.expressions[expressionName];
|
||||
if (!expression) {
|
||||
console.warn(`表情 "${expressionName}" 不存在`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.randomPlayer.play(expression);
|
||||
},
|
||||
|
||||
// 获取所有表情名称
|
||||
getExpressionNames: function() {
|
||||
return Object.keys(this.expressions).map(key => ({
|
||||
key: key,
|
||||
name: this.expressions[key].name
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// 导出到全局
|
||||
if (typeof window !== 'undefined') {
|
||||
window.ExpressionLibrary = ExpressionLibrary;
|
||||
}
|
||||
Reference in New Issue
Block a user