需求里面有个功能是汽车按着路线行驶,用动画做过一遍了,但是复用不太好用,而且代码冗余,动作僵硬,如果需要实现丝滑转弯的话需要写更多的代码,
所以我想着写个函数能够实现把参数穿进去根据点的集合移动车子,
原理,生成一条样条曲线,渲染的时候不断用样条曲线上的点更新车的位置来实现移动车子;
转向的话我这里是用切线,用两个相近的点生成一条切线,转成单位向量,用四元数处理两个单位向量(模型朝向的单位向量和切线的单位向量),最后赋值给模型的四元数就完成了
import * as THREE from "three";
export function carMove(pointNumber: number, mesh: any, points: THREE.Vector3[], camera: THREE.Camera, renderer: THREE.WebGLRenderer, scene: THREE.Scene) {
//第一个参数曲线上的点,点越多,移动的越慢,mesh是小车的模型,points是车辆的参考路径,后面的就是老三样
const curve = new THREE.CatmullRomCurve3(points);
//更新下模型的方向矩阵吧,我是这么理解的
mesh.updateMatrix();
const localMatrix = mesh.matrix.clone();
const forwardVector = new THREE.Vector3();
// 获取模型的前方向
forwardVector.setFromMatrixColumn(localMatrix, 2);
// 单位化前方向
forwardVector.normalize();
//从第一个点出发
let pathIndex = 1;
function initAnimate() {
if (pathIndex === pointNumber-1) {
//如果你要循环执行的话把return换成重新赋值,pathIndex=0
return
}
pathIndex += 1;
//判断模型是否加载成功了
if (mesh) {
//这里其实就是获取两个相近的点,形成一个向量,近似于切线的单位向量
// 样条曲线上某个点的比值(0-1)之间
const sphereCurveIndex = pathIndex / pointNumber;
// 样条曲线上某个点的比值(0-1)之间
const sphereCurveIndex1 = (pathIndex - 1) / pointNumber;
const positionVec = curve.getPointAt(sphereCurveIndex); //获取曲线上位置的点,传值为0-1的小数表示整个线段的位置
const positionVec1 = curve.getPointAt(sphereCurveIndex1);
let tangent = new THREE.Vector3(positionVec.x - positionVec1.x, positionVec.y - positionVec1.y, positionVec.z - positionVec1.z)
tangent.normalize()
//这一行是一点点移动车的位置
mesh.position.set(positionVec.x, positionVec.y, positionVec.z);
// 这三行是让小车朝向切线方向,用到了四元数,setFromUnitVectors
const q = new THREE.Quaternion();
q.setFromUnitVectors(forwardVector, tangent);
// 把四元数赋值给模型的方向矩阵
mesh.quaternion.copy(q);
}
requestAnimationFrame(initAnimate);
renderer.render(scene, camera);
}
initAnimate()
}
这是我用的点的集合
let points = [
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(-0.2, 0, .45),
new THREE.Vector3(8, 0, 0.5),
new THREE.Vector3(20, 0, 0.5),
new THREE.Vector3(20, 0, -20),
new THREE.Vector3(5, 0, -20),
new THREE.Vector3(-2.3, 0, -20),
new THREE.Vector3(-2.3, 0, -5),
new THREE.Vector3(0, 0, -5),
new THREE.Vector3(0, 0, 0.2),
];
carMove(600, FireTruck, points, camera, renderer, scene);
大概就是这些,大家有什么可以改进的地方可以的话,给我也说下,拜托了,