前期的思路分享
为了实现模型给定像上图中蓝色的轨迹之后来回走动的效果(卫兵巡逻),我一开始的思路就是根据模型坐标和模型的下一个坐标计算出夹角(v1.angleTo(v2);加上特定的方式计算出模型向左转还是向右转),然后用模型的rotation累加累减的方式实现转向效果,实际上模型是在不停转动,并且代码繁多,十分不可取,所以分享一下我这个失败的思路。下面是成功实现效果的经验。
核心知识点
1、Matrix4 (四维矩阵):它是一个变换矩阵,可以通过它反应向量,如平移、旋转、剪切、缩放、反射、正交或透视投影等。这就是把矩阵应用到向量上。
2、Euler (欧拉角):欧拉角描述一个旋转变换,通过指定轴顺序和其各个轴向上的指定旋转角度来旋转一个物体。
3、Quaternion (四元数):根据四元数来表示旋转,这个地方我还没有搞太懂,暂时知道是这么用的。
4、.getPoint(*):获取轨迹的下一个点。
示例代码
1、根据点坐标定义轨迹,将轨迹画出来(当然也可以不画)。
let curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-650, 0, 400),
new THREE.Vector3(-650, 0, 0),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(650, 0, 0),
new THREE.Vector3(650, 0, -400)
]);
this.curve = curve;
let points = curve.getPoints(1000);
let geometry = new THREE.Geometry();
// 把从曲线轨迹上获得的顶点坐标赋值给几何体
geometry.vertices = points;
let material = new THREE.LineBasicMaterial({
color: 0x4488ff
});
let line = new THREE.Line(geometry, material);
this.scene.add(line);
2、导入模型添加动画,具体“入门六”中已经提到,所以不多做介绍。
let loader = new GLTFLoader();
loader.load('./objs/factory2/RobotExpressive.glb', (gltf) => {
let model = gltf.scene;
model.scale.set(20, 20, 20);
model.rotation.y = Math.PI;
this.mixer = new THREE.AnimationMixer(model);
let action = this.mixer.clipAction(gltf.animations[10]);
action.play();
this.robotModel = model;
this.scene.add(model);
// this.LOG.info(['gltf.animations -- ', gltf.animations]);
this.render();
});
3、animate回调里根据以上核心知识点来控制模型旋转和移动。
animate() {
if (this.controls) {
this.controls.update();
}
this.render();
requestAnimationFrame(this.animate);
if (this.mixer) {
let dt = this.clock.getDelta();
this.mixer.update(dt);
}
//添加控制开关,GO是去,BACK是回来,这样可以来回移动
if (this.robotDirection === 'GO') {
if (this.progress > 1.0) {
this.robotDirection = 'BACK'
} else {
this.progress += 0.0009;
}
} else {
if (this.progress < 0) {
this.robotDirection = 'GO'
} else {
this.progress -= 0.0009;
}
}
if (this.curve && this.robotModel) {
let point = this.curve.getPoint(this.progress);
//模型的偏移量
let offsetAngle = Math.PI;
//创建一个4维矩阵
let mtx = new THREE.Matrix4();
mtx.lookAt(this.robotModel.position.clone(), point, this.robotModel.up);
mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)));
//计算出需要进行旋转的四元数值
let toRot = new THREE.Quaternion().setFromRotationMatrix(mtx);
//根据以上值调整角度
this.robotModel.quaternion.slerp(toRot, 0.2);
this.robotModel.position.set(point.x, point.y, point.z);
}
},
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}