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 = thisloader.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 );
这样才算一个较为完整的动画效果,
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 );
然后再来看下效果
MMD动画2