VUE2——three.js模型渲染

 vue2项目——模型渲染——点击特定物体物体发光——播放模型自带动画

依赖安装

  1.  three

  2. three-gltf-loader

  3. three-orbitcontrols

  4. 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;
},

 

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值