vue2项目——模型渲染——点击特定物体物体发光——播放模型自带动画
依赖安装
-
three
-
three-gltf-loader
-
three-orbitcontrols
-
package.json文件 "three": "^0.161.0", "three-gltf-loader": "^1.111.0", "three-orbitcontrols": "^2.110.3",
模型文件放入项目
vue页面引入依赖
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js";
import { ThreeMFLoader } from "three/examples/jsm/loaders/3MFLoader.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { AnimationMixer } from "three/src/animation/AnimationMixer.js";
Data定义变量
// 模型加载中
loading: null,
// 画布
container: null,
// 场景
scene: null,
//模型
model: null
初始化模型(写在函数中按需调用)
// 获取容器
this.container = this.$refs.canvas;
// 创建场景
this.scene = new THREE.Scene();
// 场景定位
this.scene.position.set(0, -30, 0);
//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(4000);
this.scene.add(axesHelper);
//光源设置(可设置多个光源)
// 创建一个方向光源,颜色为白色,强度为20
const directionalLight = new THREE.DirectionalLight(0xffffff, 3);
directionalLight.position.set(0, 100, 200); // 设置光源的位置
this.scene.add(directionalLight); // 将光源添加到场景中
// 创建一个环境光源,颜色为白色,强度为1
const ambient = new THREE.AmbientLight(0xffffff, 10);
this.scene.add(ambient); // 将环境光源添加到场景中
// 创建一个点光源,颜色为白色,强度为1,范围为80,衰减系数为1
const pointLight = new THREE.PointLight(0xffffff, 15, 200, 0.2);
pointLight.position.set(0, 200, 0); // 设置光源的位置
this.scene.add(pointLight); // 将光源添加到场景中
// 创建一个聚光灯,颜色为白色,强度为1000
const spotLight = new THREE.SpotLight(0xffffff, 5000);
spotLight.position.set(50, 500, 0); // 设置聚光灯的位置为(50, 500, 0)
spotLight.target.position.set(1000, 100, 1000); // 设置聚光灯的照射目标的位置为(0, 100, 0)
spotLight.angle = Math.PI / 8; // 设置聚光灯的光照角度为45度
spotLight.penumbra = 1; // 设置聚光灯的过渡区域为20%
scene.add(spotLight); // 将聚光灯添加到场景中
// 创建相机
// 创建一个透视相机对象
this.camera = new THREE.PerspectiveCamera(
65, // 视角
this.container.offsetWidth / this.container.offsetHeight, // 宽高比
0.1, // 近平面距离
1000 // 远平面距离
);
// 设置相机的位置
this.camera.position.set(100, 50, 120);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true,
powerPreference: "high-performance"
});
// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setSize(
this.container.offsetWidth,
this.container.offsetHeight,
false
);
renderer.setPixelRatio(window.devicePixelRatio);
// 设置渲染器的清除颜色为透明
renderer.setClearColor(0x000000, 0); // 将0设置为透明
// 将渲染器输出添加到页面中
this.container.appendChild(renderer.domElement);
// 新建一个 加载器(对应模型格式类型,这里作用的时FBX格式模型)
// const loader = new GLTFLoader();
// const loader = new ThreeMFLoader();
const loader = new FBXLoader();
// 导入模型
const self = this;
loader.load(
`/models/Catwalk_Walk_Forward_HighKnees.fbx`,//模型路径
//加载成功后的返回函数
function(model) {
// 将传入的model赋值给self.model
self.model = model;
// 将self.model添加到场景中
self.scene.add(self.model);
// 设置场景的缩放比例为0.065
self.scene.scale.set(0.065, 0.065, 0.065);
// 添加相机控件
const controls = new OrbitControls(self.camera, renderer.domElement);
controls.autoRotate = false; // 自动旋转
controls.enableDamping = true; // 鼠标阻尼效果
controls.dampingFactor = 0.05; // 鼠标阻尼系数
controls.rotateSpeed = 0.5; // 旋转速度
controls.zoomSpeed = 1.2; // 缩放速度
controls.enablePan = true; // 禁用平移
// 创建射线投射器
const raycaster = new THREE.Raycaster();
// 监听点击事件
window.addEventListener("click", onClick);
// 创建发光材质(点击物体把发光材质添加上去)
var glowMaterial = new THREE.MeshBasicMaterial({
color: 0x00ffff,
transparent: true,
opacity: 0.5
});
// 创建一个计时器对象用于计算时间差
const clock = new THREE.Clock();
// 创建一个动画混合器对象,用于管理模型的动画
const mixer = new AnimationMixer(model);
// 获取模型的第三个动画数据
const action = mixer.clipAction(model.animations[2]);
// 播放动画
action.play();
// 设置目标播放位置为13秒
const desiredTime = 13;
// 设置动画的播放位置为目标播放位置
action.time = desiredTime;
// 模型物体点击后的逻辑
function onClick(event) {
// 计算鼠标点击位置在屏幕上的坐标
const mouse = new THREE.Vector2();
const rect = renderer.domElement.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = (-(event.clientY - rect.top) / rect.height) * 2 + 1;
// 更新射线投射器的位置和方向
raycaster.setFromCamera(mouse, self.camera);
// 检测射线和场景中的物体相交
const intersects = raycaster.intersectObjects(
self.scene.children,
true
);
if (intersects.length > 0) {
// clickedObject是点击到的第一个物体
const clickedObject = intersects[0].object;
// 调用点击物体发光的方法,参数:(点击的物体,发光材质,场景)
self.modeClickLuminous(
clickedObject,
glowMaterial,
self.scene
);
} else {
// 点击到了空白处,取消当前选中物体的发光效果
if (self.previousSelectedObject) {
self.scene.remove(self.previousSelectedObject);
self.previousSelectedObject = null;
}
}
}
// 渲染循环
function animate() {
// 请求浏览器在下一次重绘之前调用指定的函数来更新动画(必要)
requestAnimationFrame(animate);
// 更新控制器,根据用户输入更新相机位置(必要)
controls.update();
// 渲染场景,将场景中的物体投影到屏幕上(必要)
renderer.render(self.scene, self.camera);
// 计算时间差(动画)
const delta = clock.getDelta();
// 更新动画混合器,根据时间差更新动画状态(动画)
mixer.update(delta);
}
//执行渲染循环
animate();
// 模型加载完成后关闭加载动画
self.loading.close();
}
// 加载过程中函数
function(xhr) {
// 获取加载的百分比进度
const percent = xhr.loaded / xhr.total;
var percentage = (percent * 100).toFixed(2) + "%";
// elemen-ui的加载动画,加载的时候调用动画
self.loading = self.$loading({
lock: true,
text: "Loading",
spinner: "el-icon-loading",
text: `模型加载中`,
background: "rgba(0, 0, 0, 0.7)"
});
}
);
模型点击发光
modeClickLuminous(clickedObject, glowMaterial, scene) {
// 取消之前物体的发光效果
scene.remove(this.previousSelectedObject);
// 创建发光轮廓(复制选中物体并应用发光材质)
const outline = clickedObject.clone();
outline.material = glowMaterial;
// 添加发光轮廓到场景中
scene.add(outline);
// 更新前一个选中物体
this.previousSelectedObject = outline;
}
销毁模型方法
destroyModel() {
// 从场景中移除模型
this.scene.remove(this.model);
// 释放模型占用的内存
this.model.traverse(function(object) {
if (object.geometry) {
object.geometry.dispose();
}
if (object.material) {
if (Array.isArray(object.material)) {
object.material.forEach(function(material) {
material.dispose();
});
} else {
object.material.dispose();
}
}
});
// 清空模型变量
this.model = null;
},