一,原理
1.必备对象:路径和移动物体
2.需要考虑的情况:
- 物体移动方向和位置必须受路径约束
- 物体的旋转方向是否受路径约束
3.物体的旋转方向若要受路径约束,有两种实现方式:
-
硬旋转:物体旋转角度和其所在线段的方向匹配(假设路径是由线段组成的)。
- 物体在拐点处的旋转比较僵硬。
-
软旋转:在路径上,获取距离物体一定距离的点,以此点为目标点,让物体朝向这个点。
- 物体在拐点处的旋转是有过度的,转折圆滑。
二,示例:用three.js 实现软旋转的路径跟随
此示例需要three.js 基础,对于three.js 环节,我只做简单概述。
1.搭建场景
const canvas = document.querySelector('#c');
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const renderer = new THREE.WebGLRenderer({canvas});
renderer.setSize(width, height, false);
const fov = 45;
const aspect = width / height;
const near = 0.01;
const far = 10;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 2, 0);
camera.updateProjectionMatrix();
const controls = new THREE.OrbitControls(camera, canvas);
const scene = new THREE.Scene();
2.绘制路径
let curve;
let curveObject;
{
const points = [
[0.5,0,0.5],
[-0.5,0,0.5],
[-0.5,0,-0.5],
];
curve = new THREE.CatmullRomCurve3(
points.map((p, ndx) => {
return (new THREE.Vector3()).set(...p);
}),
true,
'catmullrom',
0.01
);
{
const points = curve.getPoints(6);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({color: 0xff0000});
curveObject = new THREE.Line(geometry, material);
scene.add(curveObject);
};
}
- THREE.CatmullRomCurve3 是一种数学概念上的曲线,它若想被显示出来,还要被细分成n 条线段。
- curve.getPoints(6) 就是获取将曲线细分成六段后的定点集合。
- BufferGeometry().setFromPoints(points) 是用顶点建模,后面的线性材质和网格就不细说了。
3.建立运动物体
let car;
{
const geometry =new THREE.BoxBufferGeometry(.1,.1,.2);
const material = new THREE.MeshBasicMaterial( {color: 0xcccccc} );
car = new THREE.Mesh( geometry, material );
scene.add(car);
}
4.路径跟随动画
//汽车位置
const carPosition = new THREE.Vector3();
//汽车目标点
const carTarget = new THREE.Vector3();
function render(time) {
//将递增的时间转化为距离
let distance = time*0.0002; // convert to seconds
{
//目标点到目标的距离
const targetOffset = 0.1;
//从曲线上获取汽车点位。getPointAt 详情查手册。
curve.getPointAt(distance % 1, carPosition);
//从曲线上获取汽车目标点位
curve.getPointAt((distance + targetOffset) % 1, carTarget);
//汽车定位
car.position.copy(carPosition);
//实现软旋转
car.lookAt(carTarget);
//此方法还可以实现软位移
//car.position.lerpVectors(carPosition, carTarget, 0.5);
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
5.完整代码
<!DOCTYPE html>
<html>
<head>
<title>路径跟随</title>
<style>
html, body {
margin: 0;
height: 100%;
}
#c {
width: 100%;
height: 100%;
display: block;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>
<script>
const canvas = document.querySelector('#c');
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const renderer = new THREE.WebGLRenderer({canvas});
renderer.setSize(width, height, false);
const fov = 45;
const aspect = width / height;
const near = 0.01;
const far = 10;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 2, 0);
camera.updateProjectionMatrix();
const controls = new THREE.OrbitControls(camera, canvas);
const scene = new THREE.Scene();
let curve;
let curveObject;
{
const points = [
[0.5,0,0.5],
[-0.5,0,0.5],
[-0.5,0,-0.5],
];
curve = new THREE.CatmullRomCurve3(
points.map((p, ndx) => {
return (new THREE.Vector3()).set(...p);
}),
true,
'catmullrom',
0.01
);
{
const points = curve.getPoints(6);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({color: 0xff0000});
curveObject = new THREE.Line(geometry, material);
scene.add(curveObject);
};
}
let car;
{
const geometry =new THREE.BoxBufferGeometry(.1,.1,.2);
const material = new THREE.MeshBasicMaterial( {color: 0xcccccc} );
car = new THREE.Mesh( geometry, material );
scene.add(car);
}
//汽车位置
const carPosition = new THREE.Vector3();
//汽车目标点
const carTarget = new THREE.Vector3();
function render(time) {
//将递增的时间转化为距离
let distance = time*0.0002; // convert to seconds
{
//目标点到目标的距离
const targetOffset = 0.1;
//从曲线上获取汽车点位。
curve.getPointAt(distance % 1, carPosition);
//从曲线上获取汽车目标点位
curve.getPointAt((distance + targetOffset) % 1, carTarget);
//汽车定位
car.position.copy(carPosition);
//实现软旋转
car.lookAt(carTarget);
//此方法还可以实现软位移
//car.position.lerpVectors(carPosition, carTarget, 0.5);
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
</script>
</body>
</html>
参考网址:https://threejsfundamentals.o…
发表回复