<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A-Frame with three-vrm (Timing Fixed)</title>
<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.158.0/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@pixiv/three-vrm@1.0.12/dist/three-vrm.js"></script>
</head>
<body>
<a-scene>
<a-sky color="#ECECEC"></a-sky>
<a-plane position="0 0 -4" rotation="-90 0 0" width="10" height="10" color="#7BC8A4"></a-plane>
<a-light type="ambient" color="#888"></a-light>
<a-light type="directional" color="#FFF" intensity="0.6" position="-1 1.5 1"></a-light>
<a-entity
vrm-loader="src: ./vrm/tesA1_V0a.vrm; scale: 1.5; animSrc: ./motion/walking.glb;"
position="0 0 -4">
</a-entity>
<a-camera position="0 1.6 0"></a-camera>
</a-scene>
<script>
// DOMのすべてのコンテンツが読み込まれて準備完了になってから処理を開始する
window.addEventListener('DOMContentLoaded', () => {
AFRAME.registerComponent('vrm-loader', {
schema: {
src: { type: 'string' },
scale: { type: 'number', default: 1.0 },
animSrc: { type: 'string' }
},
init: function () {
const el = this.el;
const data = this.data;
this.vrm = null;
this.mixer = null;
// この時点でTHREE, GLTFLoader, THREE_VRMは確実に読み込まれている
const vrmLoader = new THREE.GLTFLoader();
vrmLoader.register((parser) => new THREE_VRM.VRMLoaderPlugin(parser));
vrmLoader.load(
data.src,
(gltf) => {
this.vrm = gltf.userData.vrm;
el.setObject3D('vrm', this.vrm.scene);
const scale = data.scale;
this.vrm.scene.scale.set(scale, scale, scale);
console.log('VRM model loaded successfully.');
if (data.animSrc) {
this.loadAnimation(data.animSrc);
}
},
undefined,
(error) => console.error('Failed to load VRM model:', error)
);
},
loadAnimation: function(url) {
const animLoader = new THREE.GLTFLoader();
animLoader.load(url, (gltf) => {
this.mixer = new THREE.AnimationMixer(this.vrm.scene);
const clip = gltf.animations[0];
if (!clip) {
console.warn('Animation file does not contain any animation clips.');
return;
}
const action = this.mixer.clipAction(clip);
action.play();
console.log('Animation loaded and started.');
},
undefined,
(error) => console.error('Failed to load animation:', error));
},
tick: function (time, timeDelta) {
const deltaSeconds = timeDelta / 1000;
if (this.vrm) {
this.vrm.update(deltaSeconds);
}
if (this.mixer) {
this.mixer.update(deltaSeconds);
}
}
});
});
</script>
</body>
</html>
使用変数
-------( Function ) | |
action | |
animLoader | |
charset | |
clip | |
color | |
data | |
deltaSeconds | |
el | |
height | |
intensity | |
loader | |
mixer | |
position | |
rotation | |
scale | |
src | |
type | |
url) { const animLoader = new THREE.GLTFLoader -------( Function ) | |
vrm | |
vrmLoader | |
width |