原因:threejs在运用的时候因为是没有html全都是js,所以我想把每个模型都分成不同的service来处理,而且事件也分离到自己的service里面
附加模型下载地址:传送门
结构事例(有点乱没整理求不要骂)
下面直接上代码吧
1、新建ng项目(不多说了);
2、新建一个base.ts (angular8+threejs 入坑文中有详细说明),主要是用于存放一些threejs场景的基本元素:渲染器、场景、灯光、相机、网格、性能检测 和 主要画布的搭建
3、新建一个skeleton.service(这里面包括了骨骼、模型的动画调用)
import { Injectable } from '@angular/core';
import { SkeletonHelper, AnimationMixer, Clock, AnimationAction} from 'three';
import { SCENE} from '../config/base';
import { GLTFLoader } from 'three-full';
@Injectable({
providedIn: 'root'
})
export class SkeletonService {
action: AnimationAction; // 动画动作
constructor() {
}
/**
* @ name 控制动画开始和暂停
* @ param e 回调开关
*/
isPlay(e: boolean) {
this.action.paused = e;
}
addSkeleton() {
let mixer;
const loader = new GLTFLoader();
loader.load('assets/model/people/CesiumMan.glb', (gltf) => {
// 把模型添加到场景中,SCENE是从base.ts导入的
SCENE.add(gltf.scene);
// 显示模型骨架
const skeletonHelper = new SkeletonHelper(gltf.scene);
skeletonHelper.material['linewidth'.toString()] = 2;
SCENE.add(skeletonHelper);
// 调用模型动画
mixer = new AnimationMixer(gltf.scene);
this.action = mixer.clipAction(gltf.animations[0]); // gltf.animations[0]模型里面的第一个动作
this.action.play(); // 必须要play()动画才会播放
// 监听单个动画结束回调
mixer.addEventListener('loop', (e) => {
console.log(e);
console.log('结束');
});
},
undefined,
(error) => {
console.error(error);
});
// 定义时间,这个必须要写在const render 的外面,因为render是不停刷新的如果写在里面会不停重置
const delta = new Clock();
// 本模型的渲染事件可以分离到这里
const render = () => {
requestAnimationFrame(render);
// RENDERER.render(SCENE, CAMERA); 这个 只需要写在canva.ts那边就可以了,这边不用写
if (mixer) {
mixer.update(delta.getDelta());
}
};
render();
}
}
4、回到canva的init() 直接调用 skeleton.service.ts 的 addSkeleton(); 就可以运行了
5、给模型添加动作的暂停开始操作
canva.html(可能会出现看不到按钮的情况,注意设置浮动)
<input type="button" value="on/off" (click)="player()"></pre>
canva.ts
play = false;
player() {
this.play = !this.play;
this.sk.isPlay(this.play); // 调用skeleton.service.ts 的方法
}
点击按钮就可以控制动画的继续和暂停了
总结:这样就可以把事件和模型单独分离成多个ts了,不会导致代码混乱,如果有更好的方法欢迎大家留言讨论
2019.08.19更改
文中skeleton.service 里面有个地方写得不对
就是动画更新这块,这个不应该写在这里,应为在多个文件进行requestAnimationFrame的画性能会有影响,性能显示不平滑,出现锯齿状。
解决办法:可以定义一个全局变量,然后去canvas那边统一进行更新。