<script setup lang="ts">
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { onMounted } from "vue";
let curve: any = null,
model: any = null;
let progress = 0; // 物体运动时在运动路径的初始位置,范围0~1
const velocity = 0.001; // 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率
let curve: any = null,
model: any = null;
let progress = 0; // 物体运动时在运动路径的初始位置,范围0~1
const velocity = 0.001; // 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率
onMounted(() => {
init();
animate();
// 创建一个封闭的运动轨迹
createTrace();
// 物体沿线移动方法
objectMovement();
// 汽车模型
loadingModel();
});
一 ,创建一个封闭的运动轨迹
// 创建一个封闭的运动轨迹
function createTrace() {
// 创建一个封闭的运动轨迹
curve = new THREE.CatmullRomCurve3(
[
new THREE.Vector3(-210, 2, 53), // x -150, y 2, z 50
new THREE.Vector3(150, 2, 53),
new THREE.Vector3(150, 2, 66),
new THREE.Vector3(-210, 2, 66),
],
false
);
curve.curveType = "catmullrom";
curve.closed = true; //设置是否闭环
curve.tension = 0.1; //设置线的张力,0为无弧度折线
// 为曲线添加材质在场景中显示出来,不显示也不会影响运动轨迹,相当于一个Helper
const points = curve.getPoints(50);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0x000000 });
material.transparent = true; // 启用透明
material.opacity = 0; // 设置为完全透明
// 创建要添加到场景中的最后一个对象
const curveObject = new THREE.Line(geometry, material);
scene.add(curveObject);
}
二,模型沿线移动的方法
// 物体沿线移动方法
function objectMovement() {
if (curve == null || model == null) {
console.log("Loading");
} else {
if (progress <= 1 - velocity) {
const point = curve.getPointAt(progress); //获取样条曲线指定点坐标
const pointBox = curve.getPointAt(progress + velocity); //获取样条曲线指定点坐标
if (point && pointBox) {
model.position.set(point.x, point.y, point.z);
model.lookAt(pointBox.x, pointBox.y, pointBox.z);//因为这个模型加载进来默认面部是正对Z轴负方向的,所以直接lookAt会导致出现倒着跑的现象,这里用重新设置朝向的方法来解决。
var targetPos = pointBox; //目标位置点
var offsetAngle = 1; //目标移动时的朝向偏移
// 以下代码在多段路径时可重复执行
var mtx = new THREE.Matrix4(); //创建一个4维矩阵
// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。
// console.log('@model.position',model.position)
mtx.lookAt(model.position,targetPos, model.up ); //设置朝向
mtx.multiply(
new THREE.Matrix4().makeRotationFromEuler(
new THREE.Euler(0, offsetAngle, 0)
)
);
var toRot = new THREE.Quaternion().setFromRotationMatrix(mtx); //计算出需要进行旋转的四元数值
model.quaternion.slerp(toRot, 0.75);
}
progress += velocity;
} else {
progress = 0;
}
}
}
三,加载模型
// 小米汽车
const loadingModel= () => {
const loader = new GLTFLoader();
loader.setPath("/public/data/gltf/"); // 模型路劲
loader.load("JZ10.gltf", function (gltf: any) {
gltf.scene.position.set(-140, 2, 50); // 模型位置
gltf.scene.traverse(function (child: any) {
if (child.isMesh) {
child.castShadow = true; //阴影
child.receiveShadow = true; //接受别人投的阴影
}
});
// 设置模型的大小
const modelScale = 3.5; // 定义模型的缩放比例
gltf.scene.scale.set(modelScale, modelScale, modelScale);
// gltf.scene.rotation.y = Math.PI; // 模型旋转180
// gltf.scene.rotateY(Math.PI / 2);
scene.add(gltf.scene);
model = gltf.scene;
});
};
const animate = () => {
requestAnimationFrame(animate);
moveOnCurve();
renderer.render(scene, camera);
// render();
};
最后看结果
5