項(xiàng)目信息
版本: "three": "^0.147.0"
模型來源:https://www.aplaybox.com
完整項(xiàng)目: https://github.com/yuban12315/hutao

demo 效果
首先需要初始化場(chǎng)景,攝像機(jī),渲染器,光照等,然后我們使用 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 等),如果只要加載一個(gè)靜態(tài)的模型,可以使用 new MMDLoader().load 方法,加載帶動(dòng)作的模型則可以使用 loadWithAnimation 方法。兩者都需要在回調(diào)函數(shù)中將模型的 mesh 添加到場(chǎng)景中。
也可以單獨(dú)使用 loadAnimation 加載動(dòng)畫,這里用來加載相機(jī)的動(dòng)畫。
當(dāng)相機(jī)綁定上動(dòng)畫后,在每次渲染時(shí)都會(huì)根據(jù)動(dòng)畫的內(nèi)容更新相機(jī)的位置,角度等,但此時(shí)你仍然可以給相機(jī)綁定控制器,通過用戶輸入來移動(dòng)相機(jī)。
initControls() {
const controls = new OrbitControls(
camera.getCamera(),
renderer.getRenderer().domElement
);
// 使用了 OrbitControls,camera 對(duì)象的 lookAt 方法失效
// 這里通過調(diào)整 controls.target 控制初始攝像機(jī)的位置
controls.target = new THREE.Vector3(1.6, 14, -4);
this.controls = controls;
}
這里的 MMDAnimationHelper 用來處理模型的動(dòng)畫效果,將需要綁定動(dòng)畫的對(duì)象和動(dòng)畫傳遞進(jìn)去后,還需要在渲染時(shí)調(diào)用 helper.update 方法更新動(dòng)畫效果:
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();
});
}
加載依賴,動(dòng)畫效果中的物理效果需要使用 ammo.js, 這里可以項(xiàng)目中引入并初始化。
<script src="./public/ammo.js">
Ammo().then(function (AmmoLib) {
Ammo = AmmoLib;
init(); animate();
})
</script>