Threejs加载MMD

简介: 这篇文章详细介绍了如何在Three.js中加载和使用MMD(MikuMikuDance)模型,包括模型的导入、动画的播放以及与MMD相关的文件格式和操作流程。

MMD全称MikuMikuDance,是一个简单的做动画的程序,做MMD之前先了解下什么是PMD。

PMD(Polygon Model Data)文件是一种用于描述三维模型的文件格式。PMD 文件通常用于 MikuMikuDance(MMD)软件,它是一款在日本非常流行的三维角色动画制作工具。PMD 文件包含了模型的几何形状、材质、骨骼和动画数据等信息,可以被导入到 MMD 中进行编辑和动画制作。PMD 文件是一种比较常见的三维模型文件格式,在虚拟角色创作和动画制作方面得到广泛应用。

之前我以为其他模型和gltf一样,加载进来可以显示,如果有动画可以播放动画,后来在官网看到mmd发现还是有区别的,因为他做好了统一的骨骼模型,然后动作文件是vmd格式分开的,这就意味着可以加载一个模型后选择不同的动作动画,然后实现不同的动画效果,而只需要切换动画就好了,下面引用官网的例子,结合vue来实现一下:

因为是基于Threejs的,所以还是需要创建threejs的基础场景,包括场景,相机,灯管等:

 initScene(){
      this.scene = new THREE.Scene();
      this.clock = new THREE.Clock();
      const gridHelper = new THREE.PolarGridHelper( 30, 0 );
      this.scene.add(gridHelper)
    },
    initCamera(){
      this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
      this.camera.position.set(100,100,100);
      this.camera.lookAt(0,0,0);

      this.listener = new THREE.AudioListener();
      this.camera.add( this.listener );
      this.scene.add( this.camera );
    },
    initLight(){
      //添加两个平行光
      const directionalLight1 = new THREE.DirectionalLight(0xffffff, 1.5);
      directionalLight1.position.set(-300,-300,600)
      this.scene.add(directionalLight1);
      const directionalLight2 = new THREE.DirectionalLight(0xffffff, 1.5);
      directionalLight2.position.set(600,200,600)
      this.scene.add(directionalLight2);
    },
initRenderer(){
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.container = document.getElementById("container")
      this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
      this.renderer.setClearColor('#FFFFFF', 1.0);
      this.container.appendChild(this.renderer.domElement);
    },
    initControl(){
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);//创建控制器
      this.controls.enableDamping = true;
      this.controls.maxPolarAngle = Math.PI / 2.2;      // // 最大角度
      this.controls.target = new THREE.Vector3(0, 0, 0);
      this.camera.position.set(100, 100, 100);
      this.camera.lookAt(0, 0, 0);
    },
    initAnimate() {
      requestAnimationFrame(this.initAnimate);
      this.renderer.render(this.scene, this.camera);
      if ( this.ready ) {
        this.helper.update( this.clock.getDelta() );
      }
    },

有了这个空间后,需要先引入mmd的加载器,用来加载PMD的模型文件。也包括MMD的动画助手插件用来渲染动画,两个插件加载不分先后顺序,第一个是把模型加载进来,第二个是做出动画效果。

import {MMDLoader} from "three/examples/jsm/loaders/MMDLoader";
import {MMDAnimationHelper} from "three/examples/jsm/animation/MMDAnimationHelper";

有了这两个组件后,就可以开始着手加载模型和动画了,首先,我们创建一个MMDAnimationHelper和MMDLoader的实例,然后利用MMDLoader的loadWidthAnimation方法加载模型和动画,loadWidthAnimation包括多个参数:modelUrl : String, vmdUrl : String, onLoad : Function, onProgress : Function, onError : Function,第一个也就是模型地址,第二个是动作文件地址,第三个是加载函数,第四个是加载进度,如果模型大的话可以在这里获取到加载进度,做成进度条,最后一个是加载错误的处理方法,

 this.helper = new MMDAnimationHelper();
      const loader = new MMDLoader();
      let _this = this

      loader.loadWithAnimation( '/static/tuote/tuote.pmx', '/static/tuote/12.vmd', function ( mmd ) {
        _this.scene.add( mmd.mesh );
        _this.helper.add( mmd.mesh, {
          animation: mmd.animation,
          physics: true
        });
      }, null, null );

然后,你的浏览器上就会出现一个会动的小姑娘,

我们可以用官网例子的方式加上PolarGridHelper,做出脚底光环的效果

      const gridHelper = new THREE.PolarGridHelper( 30, 0 );
      this.scene.add(gridHelper)

接着我们可以加入相机动画,制作比较动感的视觉效果,就像动画中也会有镜头拉近,拉远,等各个角度的变换拍摄,加载好相机动画后就可以看到相机也会不断地切换角度拍摄

      loader.loadAnimation( '/static/animal/wavefile_camera.vmd', this.camera, function ( cameraAnimation ) {
        _this.helper.add( _this.camera, {
          animation: cameraAnimation
        } );
      }, null, null );

这还不够,好看的画面得配上音乐,所以,我们再添加进音乐

      new THREE.AudioLoader().load( '/static/animal/wavefile_short.mp3', function ( buffer ) {
        const audio = new THREE.Audio( _this.listener ).setBuffer( buffer );
        const audioParams = { delayTime: 160 * 1 / 30 };
        _this.helper.add( audio, audioParams );
        _this.ready = true;
      }, null, null );

这样才算一个较为完整的动画效果,
WechatIMG130.jpg
MMD动画

这里不支持上传视频,我就上传个图片了,如果想看动态效果可以私我,我发给你视频

下面我们尝试切换一个动作文件,其实只需要改变动作文件的引用就好了


      loader.loadWithAnimation( '/static/animal/miku_v2.pmd', '/static/tuote/12.vmd', function ( mmd ) {
        _this.scene.add( mmd.mesh );
        _this.helper.add( mmd.mesh, {
          animation: mmd.animation,
          physics: true
        });
      }, null, null );

然后再来看下效果
WechatIMG126.jpg
MMD动画2

这里不支持上传视频,我就上传个图片了,如果想看动态效果可以私我,我发给你视频

相关文章
|
存储 缓存 Linux
free命令详解
`free`命令在Linux中显示内存使用详情,包括总内存(`total`)、已用(`used`,含缓存`buffers/cache`)、空闲(`free`)、共享(`shared`)和可用(`available`)内存。交换空间显示其总量、使用量和剩余量。`-h`选项以易读格式显示,`-m`以MB显示,`-t`显示总和,`-s`定时刷新。例如,`free -ht 5`每5秒更新内存和交换空间的总览。
898 3
|
存储 Java 数据安全/隐私保护
解放配置之道:Spring引入外部属性文件
【4月更文挑战第20天】
344 0
|
存储 缓存 容灾
AIGC 商业化道路探索 - Stable Diffusion 商业化应用(下)
Stable Diffusion 应用到商业领域的案例越来越多,商用场景下的技术架构应当如何构建?本文基于阿里云近期的一个 Stable Diffusion 商业案例,对大规模底模切换、大量 LoRA 调优的场景提出一个商业场景适用的技术架构,并已实现部署交付,稳定运行。
|
JavaScript
Threejs实现PMD模型眨眼说话等功能
这篇文章详细介绍了如何在Three.js中实现PMD模型的眨眼和说话等动态效果,通过控制模型的关键帧来模拟面部表情的变化。
799 0
Threejs实现PMD模型眨眼说话等功能
|
人工智能 Java API
MCP客户端调用看这一篇就够了(Java版)
本文详细介绍了MCP(Model Context Protocol)客户端的开发方法,包括在没有MCP时的痛点、MCP的作用以及如何通过Spring-AI框架和原生SDK调用MCP服务。文章首先分析了MCP协议的必要性,接着分别讲解了Spring-AI框架和自研SDK的使用方式,涵盖配置LLM接口、工具注入、动态封装工具等步骤,并提供了代码示例。此外,还记录了开发过程中遇到的问题及解决办法,如版本冲突、服务连接超时等。最后,文章探讨了框架与原生SDK的选择,认为框架适合快速构建应用,而原生SDK更适合平台级开发,强调了两者结合使用的价值。
14392 33
MCP客户端调用看这一篇就够了(Java版)
|
JavaScript 前端开发 开发者
ThreeJs控制模型骨骼实现数字人
这篇文章讲解了如何使用Three.js通过控制模型的骨骼来实现数字人的动态表现,包括加载模型、获取骨骼信息以及通过编程控制骨骼动作的具体方法。
1996 1
|
运维 网络安全 数据安全/隐私保护
Nextcloud一键部署:快速搭建如企业钉钉或飞书的团队协作平台
Nextcloud Hub 是一款来自德国的完全开源的云上托管内容协作平台。团队内成员可以通过移动、桌面和 Web 界面访问、共享和编辑文档,聊天和参与视频通话以及管理邮件、日历和项目。目前,Nextcloud的产品定位是在保障数据安全下的完整协作平台,功能类似国内的企业钉钉或飞书。Nextcloud官网:[https://nextcloud.com/](https://nextcloud.com/) 。
Nextcloud一键部署:快速搭建如企业钉钉或飞书的团队协作平台
|
前端开发 JavaScript
JS-instanceof 的实现原理
`instanceof` 运算符在前端 JavaScript 中用于检测对象的原型链是否包含指定构造函数的 `prototype` 属性。它通过遍历对象的原型链来实现。每个对象都有一个内部链接 `[[Prototype]]` 指向其原型对象,当访问属性或方法时,JavaScript 引擎会沿着原型链查找。`instanceof` 的具体实现是通过比较对象的原型链中的原型与构造函数的 `prototype` 属性,直到找到匹配的原型或到达原型链的顶端。示例代码展示了如何使用 `instanceof` 检查对象的继承关系。此外,`instanceof` 可用于验证继承关系和类型检查,支持多态性。

热门文章

最新文章