<!DOCTYPE html>
<html>
<head>
<title>VRM Bone & BlendShape Sampler</title>
<meta charset="utf-8">
<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
<script src="./js/aframe-vrm.js"></script>
</head>
<body>
<a-scene>
<a-entity
id="avatar"
vrm="src: ./vrm/tesA1_V0a.vrm"
vrm-anim
position="0 0 -2"
rotation="0 30 0">
</a-entity>
<a-camera position="0 1.2 0"></a-camera>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
<script>
// ========= 1. ボーンの動きを定義 =========
const boneSamplerMotion = {
// 0-4秒: 体幹を左右にひねる
spine: {
keys: [
{ rot: [0, 0, 0], time: 0 },
{ rot: [0, 20, 0], time: 1 },
{ rot: [0, -20, 0], time: 2 },
{ rot: [0, 20, 0], time: 3 },
{ rot: [0, 0, 0], time: 4 }
]
},
// 4-8秒: 首を縦横に振る
neck: {
keys: [
{ rot: [0, 0, 0], time: 4 },
{ rot: [30, 0, 0], time: 4.5 }, // うなずく
{ rot: [-20, 0, 0], time: 5.5 }, // 見上げる
{ rot: [0, 40, 0], time: 6.5 }, // 横を向く
{ rot: [0, -40, 0], time: 7.5 }, // 反対を向く
{ rot: [0, 0, 0], time: 8 }
]
},
// 8-12秒: 右足でキックする
rightUpperLeg: {
keys: [
{ rot: [0, 0, 0], time: 8 },
{ rot: [-90, 0, 0], time: 8.5 }, // ももを上げる
{ rot: [-20, 0, 0], time: 9.5 }, // キック
{ rot: [0, 0, 0], time: 12 } // 元に戻す
]
},
rightLowerLeg: {
keys: [
{ rot: [0, 0, 0], time: 8 },
{ rot: [100, 0, 0], time: 8.5 }, // ひざを曲げる
{ rot: [0, 0, 0], time: 9.5 }, // ひざを伸ばす
{ rot: [0, 0, 0], time: 12 }
]
},
// 12-17秒: 左手で手を振る(前回の完成形)
leftUpperArm: {
keys: [
{ rot: [0,0,0], time: 12}, // この時間は直前のモーションに合わせる
{ rot: [80, -20, -15], time: 13 },
{ rot: [80, -20, -15], time: 15.5 },
{ rot: [0, 0, 0], time: 17 }
]
},
leftLowerArm: {
keys: [
{ rot: [0,0,0], time: 12},
{ rot: [0, -90, 0], time: 13 },
{ rot: [0, -100, 0], time: 13.5 },
{ rot: [0, -70, 0], time: 14.0 },
{ rot: [0, -100, 0], time: 14.5 },
{ rot: [0, -70, 0], time: 15.0 },
{ rot: [0, -90, 0], time: 15.5 },
{ rot: [0, 0, 0], time: 17 }
]
}
};
document.addEventListener('DOMContentLoaded', () => {
const avatarEl = document.querySelector('#avatar');
avatarEl.setAttribute('vrm-anim', 'idleMotion', boneSamplerMotion);
});
</script>
<script>
// ========= 2. 表情の動きを定義 =========
document.addEventListener('DOMContentLoaded', () => {
const avatarEl = document.querySelector('#avatar');
// アバターのモデルが読み込み完了したら実行する
avatarEl.addEventListener('model-loaded', (event) => {
// avatarオブジェクトを取得
const avatar = event.detail.avatar;
// 2秒後: 喜ぶ
setTimeout(() => {
avatar.setBlendShapeWeight('JOY', 1.0); // "JOY"を100%適用
}, 2000);
// 4秒後: 怒る
setTimeout(() => {
avatar.setBlendShapeWeight('JOY', 0.0); // "JOY"をリセット
avatar.setBlendShapeWeight('ANGRY', 1.0); // "ANGRY"を100%適用
}, 4000);
// 6秒後: 「あ」の口
setTimeout(() => {
avatar.setBlendShapeWeight('ANGRY', 0.0);
avatar.setBlendShapeWeight('A', 0.8); // 「あ」の口を80%適用
}, 6000);
// 8秒後: 真顔に戻る
setTimeout(() => {
avatar.setBlendShapeWeight('A', 0.0);
// NEUTRALを1.0にしてもOK
// avatar.setBlendShapeWeight('NEUTRAL', 1.0);
}, 8000);
});
});
</script>
</body>
</html>
使用変数
avatar | |
avatarEl | |
boneSamplerMotion | |
charset | |
color | |
id | |
position | |
rotation | |
src | |
vrm | |
ボーンの動きを定義 | |
表情の動きを定義 |