Three.js 导入 MMD 模型
2022-12-13 本文已影响0人
御坂12315
项目信息
版本: "three": "^0.147.0"
模型来源:https://www.aplaybox.com
完整项目: https://github.com/yuban12315/hutao
首先需要初始化场景,摄像机,渲染器,光照等,然后我们使用 MMDLoader 加载 MMD 模型。
Loader 部分
import scene from "./scene";
import * as THREE from "three";
import { MMDLoader } from "three/examples/jsm/loaders/MMDLoader.js";
import { MMDAnimationHelper } from "three/examples/jsm/animation/MMDAnimationHelper.js";
import camera from "./camera";
export const helper = new MMDAnimationHelper();
export class Loader {
loadModels() {
const loader = new MMDLoader();
loader.loadWithAnimation(
"/public/hutao/胡桃.pmx",
"/public/move/ayaka-dance.vmd",
function onLoad(mmd) {
// called when the resource is loaded
const { mesh } = mmd;
helper.add(mmd.mesh, {
animation: mmd.animation,
});
scene.getScene().add(mmd.mesh);
}
);
loader.loadAnimation(
"./public/move/ayaka-camera.vmd",
camera.getCamera(),
function (cameraAnimation) {
helper.add(camera.getCamera(), {
animation: cameraAnimation as THREE.AnimationClip,
});
}
);
}
}
export default new Loader();
在 three.js 中可以使用 MMDLoader 加载适用于 MMD 的文件(.pmx,.vmd 等),如果只要加载一个静态的模型,可以使用 new MMDLoader().load 方法,加载带动作的模型则可以使用 loadWithAnimation 方法。两者都需要在回调函数中将模型的 mesh 添加到场景中。
也可以单独使用 loadAnimation 加载动画,这里用来加载相机的动画。
当相机绑定上动画后,在每次渲染时都会根据动画的内容更新相机的位置,角度等,但此时你仍然可以给相机绑定控制器,通过用户输入来移动相机。
initControls() {
const controls = new OrbitControls(
camera.getCamera(),
renderer.getRenderer().domElement
);
// 使用了 OrbitControls,camera 对象的 lookAt 方法失效
// 这里通过调整 controls.target 控制初始摄像机的位置
controls.target = new THREE.Vector3(1.6, 14, -4);
this.controls = controls;
}
这里的 MMDAnimationHelper 用来处理模型的动画效果,将需要绑定动画的对象和动画传递进去后,还需要在渲染时调用 helper.update 方法更新动画效果:
constructor() {
const container = document.getElementById("three");
if (!container) {
return;
}
this.clock = new THREE.Clock();
scene.init(container);
camera.init(container);
renderer.init(container);
}
render() {
loader.loadModels();
// this.initControls();
this.initLight();
this.callRenderer();
}
callRenderer() {
this.frameId = requestAnimationFrame(() => {
// this.controls.update();
const time = this.clock.getDelta();
helper.update(time);
renderer.getRenderer().render(scene.getScene(), camera.getCamera());
this.callRenderer();
});
}
加载依赖,动画效果中的物理效果需要使用 ammo.js, 这里可以项目中引入并初始化。
<script src="./public/ammo.js">
Ammo().then(function (AmmoLib) {
Ammo = AmmoLib;
init(); animate();
})
</script>