0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

three.jsでanimation system その8

Last updated at Posted at 2023-07-04

概要

three.jsでanimation systemを、理解したかった。
練習問題、やってみた。

練習問題

vrmのAnimationClipをBVHから変換して適合せよ。

写真

image.png

サンプルコード


let mixer;
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(45, 500 / 400, 0.1, 1000)
camera.position.set(0, 1.2, -1.9)
camera.rotation.set(0, Math.PI, 0)
const renderer = new THREE.WebGLRenderer()
renderer.setSize(500, 400)
document.body.appendChild(renderer.domElement)
const controls = new THREE.OrbitControls(camera, renderer.domElement);
const directionalLight = new THREE.DirectionalLight('#ffffff', 1)
directionalLight.position.set(1, 1, 1)
scene.add(directionalLight)
const loader = new THREE.GLTFLoader();
loader.load('https://drumath2237.github.io/three-vrm-test/models/undefined-chan-toon.vrm',
  (gltf) => {
    THREE.VRM.from(gltf).then((vrm) => {
      scene.add(vrm.scene);
    	const loader = new THREE.BVHLoader();
	    loader.load("https://cdn.rawgit.com/una-dinosauria/cmu-mocap/master/data/001/01_01.bvh", function(bvh) {
				//console.log(bvh);
    		const clip = createClip(vrm, bvh);
				//console.log(clip);
	    	mixer = new THREE.AnimationMixer(vrm.scene);
		   	mixer.clipAction(clip).setEffectiveWeight(1.0).play();
      });
    });
  },
	(progress) => console.log("Loading model...", 100.0 * (progress.loaded / progress.total), "%"),
  (error) => console.error(error)
)
function findTrack(name, tracks) {
	for (let i = 0; i < tracks.length; i++)
	{
		if (tracks[i].name == name)
			return tracks[i];
	}
	alert(name);
	return null;
}
function values2quaternion(values, i) {
	return new THREE.Quaternion(values[i * 4], values[i * 4 + 1], values[i * 4 + 2], values[i * 4 + 3]);
}
function createKeys(id, tracks) {
	const posTrack = findTrack(".bones[" + id + "].position", tracks);
	const rotTrack = findTrack(".bones[" + id + "].quaternion", tracks);
	const keys = [];
	const rate = 0.008;
	for (let i = 0; i < posTrack.times.length; i++)
	{
		const key = {};
		key["time"] = parseInt(posTrack.times[i] * 1000);
		if (id == "RHipJoint" || id == "LHipJoint")
		{
			//console.log(id);
			const id2 = id == "LHipJoint" ? "RightUpLeg" : "LeftUpLeg";
			let q1 = values2quaternion(rotTrack.values, i);
			const rotTrack2 = findTrack(".bones[" + id2 + "].quaternion", tracks);
			q1.multiply(values2quaternion(rotTrack2.values, i));
			key["rot"] = [-q1.x, q1.y, -q1.z, q1.w];
		}
		else
		{
			key["rot"] = [-rotTrack.values[i * 4], rotTrack.values[i * 4 + 1], -rotTrack.values[i * 4 + 2], rotTrack.values[i * 4 + 3],];
		}
		if (id == "Hips")
		{
			//console.log(id);
			key["pos"] = [-posTrack.values[i * 3] * rate, posTrack.values[i * 3 + 1] * rate, -posTrack.values[i * 3 + 2] * rate,];
		}
		keys.push(key);
	}
	if (keys.length == 0)
		return null;
	return keys;
}
function createClip(vrm, bvh) {
	const nameList = [
		THREE.VRMSchema.HumanoidBoneName.Head,
		THREE.VRMSchema.HumanoidBoneName.Neck,
		THREE.VRMSchema.HumanoidBoneName.Chest,
		THREE.VRMSchema.HumanoidBoneName.Spine,
		THREE.VRMSchema.HumanoidBoneName.Hips,
		THREE.VRMSchema.HumanoidBoneName.RightShoulder,
		THREE.VRMSchema.HumanoidBoneName.RightUpperArm,
		THREE.VRMSchema.HumanoidBoneName.RightLowerArm,
		THREE.VRMSchema.HumanoidBoneName.RightHand,
		THREE.VRMSchema.HumanoidBoneName.LeftShoulder,
		THREE.VRMSchema.HumanoidBoneName.LeftUpperArm,
		THREE.VRMSchema.HumanoidBoneName.LeftLowerArm,
		THREE.VRMSchema.HumanoidBoneName.LeftHand,
		THREE.VRMSchema.HumanoidBoneName.RightUpperLeg,
		THREE.VRMSchema.HumanoidBoneName.RightLowerLeg,
		THREE.VRMSchema.HumanoidBoneName.RightFoot,
		THREE.VRMSchema.HumanoidBoneName.LeftUpperLeg,
		THREE.VRMSchema.HumanoidBoneName.LeftLowerLeg,
		THREE.VRMSchema.HumanoidBoneName.LeftFoot,
	];
	const idList = [
		"Head",
		"Neck",
		"LowerBack",
		"Spine1",
		"Hips",
		"RightShoulder",
		"RightArm",
		"RightForeArm",
		"RightHand",
		"LeftShoulder",
		"LeftArm",
		"LeftForeArm",
		"LeftHand",
		"RHipJoint",
		"RightLeg",
		"RightFoot",
		"LHipJoint",
		"LeftLeg",
		"LeftFoot"
	];
	const bones = nameList.map((boneName) => {
		return vrm.humanoid.getBoneNode(boneName);
	});
	const hierarchy = [];
	for (let i = 0; i < idList.length; i++)
	{
		const keys = createKeys(idList[i], bvh.clip.tracks);
		if (keys != null)
		{
			hierarchy.push({
				keys: keys
			});
		}
	}
	const clip = THREE.AnimationClip.parseAnimation({
		hierarchy: hierarchy
	}, bones);
	clip.tracks.some((track) => {
		track.name = track.name.replace(/^\.bones\[([^\]]+)\].(position|quaternion|scale)$/, "$1.$2");
	});
	return clip;
}
function animate() {
	requestAnimationFrame(animate);
	let time = new Date().getTime();
	if (mixer)
		mixer.update(time - lastTime);
	lastTime = time;
	renderer.render(scene, camera);
}
animate();    
    

    

成果物

以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?