1,介绍
该示例使用的是 r95版本Three.js库。
主要实现功能:创建一个管道(管道的作用主要是方便观察运动方向),镜头跟随物体移动效果,物体上下左右拐弯镜头跟随拐弯。
效果图如下:
2,实现思路
1,定义关键固定位置坐标,用固定坐标值生成一组曲线。
2,将曲线分割成多份获取分割后的一组顶点坐标
3,加载物体并设置初始位置,这里用的是个飞机模型
4,通过Threejs的帧动画实时修改物体坐标和物体朝向,达到运动效果
根据坐标生成曲线,并创建一个管道
// 通过类CatmullRomCurve3创建一个3D样条曲线 curve = new THREE.CatmullRomCurve3([ new THREE.Vector3(-1000, -5000, -5000), new THREE.Vector3(1000, -5000, 0), new THREE.Vector3(1800, 800, 1000), new THREE.Vector3(800, 5000, 5000), new THREE.Vector3(0, 0, 10000) ]); // 样条曲线均匀分割100 var points = curve.getPoints(100); var geometry = new THREE.Geometry(); // 把从曲线轨迹上获得的顶点坐标赋值给几何体 geometry.vertices = points var material = new THREE.LineBasicMaterial({ color: "#4488ff" }); var line = new THREE.Line(geometry, material); scene.add(line); //管道体 const tubeGeometry = new THREE.TubeGeometry(curve, 100, 500, 30); // 101取点数 3为r 30为三角切面数 const tubeMesh = new THREE.Mesh(tubeGeometry, new THREE.MeshBasicMaterial({ color: "#00aa00", side: THREE.DoubleSide, wireframe: true })) scene.add(tubeMesh)
加载物体模型,这里用的是个飞机模型glb格式
// 引用GLTFLoader.js文件,加载模型 var loader = new THREE.GLTFLoader(); loader.load('assets/models/feiji/feiji.glb', function(result) { mesh = result.scene; mesh.position.set(-1000, -5000, -5000); scene.add(mesh); });
实时修改物体坐标和物体朝向
function changeLookAt(t) { // 当前点在线条上的位置 const position = curve.getPointAt(t); var nPos = new THREE.Vector3(position.x, position.y - 100, position.z); mesh.position.copy(nPos); // 返回点t在曲线上位置切线向量 const tangent = curve.getTangentAt(t); // 位置向量和切线向量相加即为所需朝向的点向量 const lookAtVec = tangent.add(nPos); mesh.lookAt(lookAtVec); if (t > 0.03) { var pos = curve.getPointAt(t - 0.03); camera.position.copy(pos); camera.lookAt(position) } } var clock = new THREE.Clock(); //声明一个时钟对象 const loopTime = 10 * 1000; // loopTime: 循环一圈的时间 let i = 0; function renderScene() { // 使用requestAnimationFrame函数进行渲染 requestAnimationFrame(renderScene); renderer.render(scene, camera); if (curve) { let time = Date.now(); let t = (time % loopTime) / loopTime; // 计算当前时间进度百分比 setTimeout(function() { changeLookAt(t); }, 2000) } }