Three.js 導(dǎo)入 MMD 模型

項(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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容