junkerstock
 vrm-text-bvh6 

<!DOCTYPE html>
<html>
<head>
<title>VRM with BVH Animation Player (Module Fix)</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 renderer="physicallyCorrectLights: true">

<a-entity
id="avatar"
vrm="src: ./vrm/tesA1_V0a.vrm"
position="0 0 0"
rotation="0 180 0">
</a-entity>

<a-entity camera position="0 1.6 2.5" look-controls wasd-controls></a-entity>

<a-sky color="#ECECEC"></a-sky>
<a-plane position="0 0 0" rotation="-90 0 0" width="100" height="100" color="#FFFFFF" shadow></a-plane>
<a-light type="directional" color="#FFF" intensity="0.6" position="-1 2 2"></a-light>
<a-light type="ambient" color="#FFF" intensity="0.6"></a-light>

</a-scene>

<script type="module">
// 必要な部品(BVHLoader)だけをモジュールとしてインポートします
import { BVHLoader } from 'https://unpkg.com/three@0.158.0/examples/jsm/loaders/BVHLoader.js';

// A-Frameが準備したTHREEオブジェクトを安全に使用します
const THREE = window.THREE;

window.addEventListener('load', () => {
console.log('✅ ページ全体の読み込み完了。BVH処理を開始します。');

const BVH_URL = 'https://p-bookmark.sakura.ne.jp/junkerstock/vrm/8.bvh';
const avatarEl = document.querySelector('#avatar');

const boneMap = {
'J_Bip_C_Hips': 'hips', 'J_Bip_C_Spine': 'spine', 'J_Bip_C_Chest': 'chest',
'J_Bip_C_UpperChest': 'upperChest', 'J_Bip_C_Neck': 'neck', 'J_Bip_C_Head': 'head',
'J_Bip_L_Shoulder': 'leftShoulder', 'J_Bip_L_UpperArm': 'leftUpperArm',
'J_Bip_L_LowerArm': 'leftLowerArm', 'J_Bip_L_Hand': 'leftHand',
'J_Bip_R_Shoulder': 'rightShoulder', 'J_Bip_R_UpperArm': 'rightUpperArm',
'J_Bip_R_LowerArm': 'rightLowerArm', 'J_Bip_R_Hand': 'rightHand',
'J_Bip_L_UpperLeg': 'leftUpperLeg', 'J_Bip_L_LowerLeg': 'leftLowerLeg',
'J_Bip_L_Foot': 'leftFoot', 'J_Bip_L_ToeBase': 'leftToes',
'J_Bip_R_UpperLeg': 'rightUpperLeg', 'J_Bip_R_LowerLeg': 'rightLowerLeg',
'J_Bip_R_Foot': 'rightFoot', 'J_Bip_R_ToeBase': 'rightToes'
};

// インポートしたBVHLoaderを直接使います (THREE.BVHLoader ではない)
const loader = new BVHLoader();
loader.load(BVH_URL, (bvh) => {
console.log('✅ BVHファイルの読み込み成功。vrm-anim形式への変換を開始...');
const bvhMotion = {};

bvh.clip.tracks.forEach(track => {
const bvhNodeName = track.name.split('.')[0];
const vrmBoneName = boneMap[bvhNodeName];

if (!vrmBoneName || track.name.endsWith('.position')) {
return;
}

const keys = [];
for (let i = 0; i < track.times.length; i++) {
const time = track.times[i];
const quaternion = new THREE.Quaternion(
track.values[i * 4],
track.values[i * 4 + 1],
track.values[i * 4 + 2],
track.values[i * 4 + 3]
);
const euler = new THREE.Euler().setFromQuaternion(quaternion, 'YXZ');
keys.push({
rot: [
THREE.MathUtils.radToDeg(euler.x),
THREE.MathUtils.radToDeg(euler.y),
THREE.MathUtils.radToDeg(euler.z)
],
time: time
});
}
bvhMotion[vrmBoneName] = { keys: keys };
});

console.log('✅ 変換完了。アニメーションをモデルに適用します。');
avatarEl.setAttribute('vrm-anim', 'bvh', bvhMotion);
console.log('🎉 アニメーション適用完了!');
});
});
</script>

</body>
</html>


使用変数

avatarEl
boneMap
bvhMotion
bvhNodeName
BVH_URL
charset
color
euler
height
i
id
intensity
keys
loader
position
quaternion
renderer
rotation
src
THREE
time
track
type
vrm
vrmBoneName
width