当前位置: 首页 > news >正文

vue+three.js 加载模型,并让模型随航线飞行

        嗨,我是小路。今天主要和大家分享的主题是“vue+three.js 加载模型,并让模型随航线飞行”。        

这两天在gitee上找到一个three.js项目,主要是用来加载gltf模型,并让模型随着移动。今天主要是对这个学习过程的梳理。

项目示例图

一、主要知识点

1.setScalar

定义:主要是将THREE.Vector3中的x、y、z设置为相同的标量。

属性列表列表说明

2.turbidity

定义:浑浊度,模糊不清的程度。在计算机图形学中,turbidity 常用于模拟大气散射效果,比如天空和阳光的真实感渲染。

数值意义
0 - 1非常清晰
1-5一般清晰
5-50浑浊
>50非常浑浊

3.rayleigh

定义:光照的强度。是一个常用于物理、光学、图形渲染等领域的术语,散射的意思。主要是天空的颜色。数值在0-4之间,数值越高,蓝天越鲜艳。

属性列表列表说明
0无瑞利散射,天空呈灰色或黑色
1-2正常蓝天效果(适合晴天)
>3蓝天非常强烈,可能显得不自然

4.mieCoefficient

定义:米氏系数是控制 Mie 散射强度 的参数。用于模拟空气中较大颗粒(如灰尘、水滴、气溶胶)对光线的散射效果,主要影响日出/日落时的橙红色调。

属性列表列表说明
0没有米氏散射,天空更偏向瑞利散射效果(蓝色为主)
0.005-0.02正常大气下的柔和日光或黄昏效果
0.05 ~ 0.08天空变得更“雾蒙蒙”,阳光方向更明显,适合雾霾、沙尘天气;明显的阳光散射,适合黄昏、雾霾天
0.1+强烈的“光污染”效果,适合极端天气或风格化场景

5.mieDirectionalGlar

定义:米氏散射(Mie Scattering)的方向性,介于 -11 之间的数值。用于模拟阳光穿过大气层时,由于空气中大颗粒(如尘埃、水滴、气溶胶)导致的 前向或后向散射效果。

属性列表列表说明
0各向同性散射(光线均匀地向所有方向散射)
>0前向散射增强(光线更倾向于沿原方向传播)
<0后向散射增强(光线更倾向于反方向散射)

6.setFromSphericalCoords

定义:米氏散射(Mie Scattering)的方向性,介于 -11 之间的数值。用于模拟阳光穿过大气层时,由于空气中大颗粒(如尘埃、水滴、气溶胶)导致的 前向或后向散射效果。

注意:单位是 弧度(radians),如果你使用的是角度(degrees),记得先用 THREE.MathUtils.degToRad() 转换。

参数含义
radius半径
phi极角,从正 Y 轴向下旋转的角度,单位是弧度,需要转换
theta方位角,绕 Y 轴旋转的角度,单位是弧度,需要将角度转换为弧度

7.sunPosition

定义:太阳的位置。用于控制光线方向和散射效果,在使用 THREE.Sky 模拟大气时尤为重要

极角意义
phi = 0太阳在正上方(头顶)
phi = Math.PI / 2太阳在地平线上
phi > Math.PI / 2太阳在地平面以下(夜晚)

8.sunPosition

定义:太阳的位置。用于控制光线方向和散射效果,在使用 THREE.Sky 模拟大气时尤为重要

极角意义
phi = 0太阳在正上方(头顶)
phi = Math.PI / 2太阳在地平线上
phi > Math.PI / 2太阳在地平面以下(夜晚)

9.getPoints

定义:用于获取路径上的一系列点;点通常用于绘制线段、生成几何体轮廓、创建沿路径移动的动画。参数主要是要返回的点的数量(即路径被分成多少段)默认值:12,数值越大,点越密集,路径越平滑

10.setFromPoints

定义:它可以根据一组三维点(THREE.Vector3)创建一个几何体,常用于绘制线段、点云或自定义形状。

注意:数据量有限。太多的点容易影响性能。

11.computeLineDistances

定义:用于计算线段中每个顶点到起点的累计距离。这个功能在你需要根据线段长度进行着色、动画或渐变效果时非常有用。

应用:

1、遍历线段中的所有顶点;
2、计算从第一个顶点开始,每一段线段的累计长度;
3、将结果存储在几何体的 lineDistance 属性中(作为顶点属性);
4、可用于后续的着色器处理(如颜色渐变、粒子沿路径运动等);

12.getTangent

定义:用于获取曲线在某个参数位置上的切线方向向量。


二、实例代码

<template><div class="pageBox"></div></template>
<script setup>
import { onMounted, reactive, ref } from 'vue';
import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { Sky } from "three/examples/jsm/objects/Sky";
import { FogExp2 } from "three";let scene, camera, renderer, controls, fillLight, ambientLight, mainLight;
// 加载飞机模型
const loader = new GLTFLoader();
const initThree = () => {// 创建场景scene = new THREE.Scene();scene.fog = new THREE.FogExp2(0xdfe9f3, 0.02); // 添加雾效果// 创建相机camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.set(0, 5, 10);// 创建渲染器renderer = new THREE.WebGLRenderer({antialias: true,alpha: true,});renderer.setSize(window.innerWidth, window.innerHeight);renderer.shadowMap.enabled = true; // 启用阴影renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 使用柔和阴影renderer.toneMapping = THREE.ACESFilmicToneMapping; // 添加电影级别的色调映射renderer.toneMappingExposure = 0.5;document.body.appendChild(renderer.domElement);// 添加轨道控制器controls = new OrbitControls(camera, renderer.domElement);controls.enableDamping = true;controls.dampingFactor = 0.05;controls.maxDistance = 50;controls.minDistance = 3;// 添加光源ambientLight = new THREE.AmbientLight(0xffffff, 0.5);scene.add(ambientLight);// 主光源mainLight = new THREE.DirectionalLight(0xffffff, 1);mainLight.position.set(5, 5, 5);mainLight.castShadow = true;mainLight.shadow.mapSize.width = 2048;mainLight.shadow.mapSize.height = 2048;mainLight.shadow.camera.near = 0.1;mainLight.shadow.camera.far = 100;mainLight.shadow.camera.left = -20;mainLight.shadow.camera.right = 20;mainLight.shadow.camera.top = 20;mainLight.shadow.camera.bottom = -20;scene.add(mainLight);// 添加补光fillLight = new THREE.DirectionalLight(0x8088ff, 0.4);fillLight.position.set(-5, 3, -5);scene.add(fillLight);
}
let sky, sun, uniforms, phi, theta;
const initOther = () => {// 添加天空sky = new Sky();//将向量的 x、y 和 z 分量全部设置为指定的标量值 1000sky.scale.setScalar(1000);scene.add(sky);//阳光sun = new THREE.Vector3();uniforms = sky.material.uniforms;//清晰度uniforms["turbidity"].value = 10;//用于模拟地球天空的颜色变化和阳光的散射效果 散射颜色uniforms["rayleigh"].value = 2;//用于模拟空气中较大颗粒(如灰尘、水滴、气溶胶)对光线的散射效果 散射强度uniforms["mieCoefficient"].value = 0.005;//于模拟阳光穿过大气层时,由于空气中大颗粒(如尘埃、水滴、气溶胶)导致的 前向或后向散射效果。 散射的方向uniforms["mieDirectionalG"].value = 0.8;//将88度转化成弧度phi = THREE.MathUtils.degToRad(90 - 2);//将180度转化成弧度theta = THREE.MathUtils.degToRad(180);//设置阳光三维向量的值   半径  极角(从Y轴向下偏转) 方位角(绕Y轴旋转的角度)sun.setFromSphericalCoords(1, phi, theta);uniforms["sunPosition"].value.copy(sun);
}onMounted(() => {initThree();initOther();initModel();initLine();animate();// 处理窗口大小变化 只需要设置相机 和重新渲染window.addEventListener("resize", () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);});
})let airplane;
const initModel = () => {// 创建一个组来存放飞机模型airplane = new THREE.Group();scene.add(airplane);loader.load("./models/airplane/scene.gltf",(gltf) => {// 调整模型大小和方向gltf.scene.scale.set(0.01, 0.01, 0.01);gltf.scene.rotation.set(0, Math.PI, 0);// 为模型添加阴影gltf.scene.traverse((child) => {if (child.isMesh) {child.castShadow = true;child.receiveShadow = true;// 增强材质效果if (child.material) {child.material.envMapIntensity = 1;child.material.needsUpdate = true;}}});airplane.add(gltf.scene);},(progress) => {console.log("加载进度:", (progress.loaded / progress.total) * 100 + "%");},(error) => {console.error("模型加载出错:", error);});
}let curve, points, pathGeometry, pathMaterial, pathLine;
const initLine = () => {// 创建飞行路径curve = new THREE.CatmullRomCurve3([new THREE.Vector3(-10, 0, 0),new THREE.Vector3(-5, 4, 5),new THREE.Vector3(0, 0, 0),new THREE.Vector3(5, 4, -5),new THREE.Vector3(10, 0, 0),]);// 可视化路径(使用渐变材质)//于获取路径上的一系列点 这些点通常用于绘制线段、生成几何体轮廓、创建沿路径移动的动画points = curve.getPoints(50);//可以根据一组三维点(THREE.Vector3)创建一个几何体,常用于绘制线段、点云或自定义形状pathGeometry = new THREE.BufferGeometry().setFromPoints(points);pathMaterial = new THREE.LineDashedMaterial({color: 0xffffff,dashSize: 0.5,gapSize: 0.3,opacity: 0.5,transparent: true,});pathLine = new THREE.Line(pathGeometry, pathMaterial);pathLine.computeLineDistances(); // 计算虚线scene.add(pathLine);}// 动画参数
let progress = 0;
let speed = 0.001;// 动画循环
function animate() {requestAnimationFrame(animate);// 更新飞机位置progress += speed;if (progress > 1) progress = 0;const point = curve.getPoint(progress);airplane.position.copy(point);// 计算飞机朝向 获取曲线在某个参数位置上的切线方向向量const tangent = curve.getTangent(progress);const up = new THREE.Vector3(0, 1, 0);const matrix = new THREE.Matrix4();matrix.lookAt(new THREE.Vector3(0, 0, 0), tangent, up);airplane.quaternion.setFromRotationMatrix(matrix);// 更新控制器controls.update();// 渲染场景renderer.render(scene, camera);
}</script>
<style scoped lang="less">
.pageBox {width: 100%;//height: 100vh;padding: 0;margin: 0;display: flex;justify-content: space-between;align-items: center;.rightBox {width: 100%;height: 100%;background: yellow;}
}
</style>

三、复盘总结

       1、总共分为多个部分:天空、飞行路线、加载模型、模型随着线的方向移动、最后是屏幕缩放。

        2、在屏幕尺寸调整时,不需要重新加载模型,只需要调整相机的视图和角度,以及重新渲染就可以了,没必要再加载模型。

都看到这里了,记得【点赞】+【关注】哟。

参考文件:

http://www.lqws.cn/news/600193.html

相关文章:

  • 服务器种类与超融合
  • CSS 安装使用教程
  • mysql的自增id用完怎么办?
  • 【MobaXterm、Vim】使用合集1
  • 多容器应用与编排——AI教你学Docker
  • 单端输入转差分输出
  • ELK日志分析系统(filebeat+logstash+elasticsearch+kibana)
  • 学习字符串
  • AKAZE(Accelerated-KAZE)图像特征点检测算法详解和C++代码实现示例
  • 初识QT-对象树
  • Adobe AI高效设计秘籍与创新思维进阶
  • STM32
  • 三极管是NPN还是PNP
  • 为什么Netty 性能高
  • 关于vue2使用elform的rules校验
  • 第8章路由协议,RIP、OSPF、BGP、IS-IS
  • Zephyr RTOS 信号量 (Semaphore)
  • SpringMVC--使用RESTFul实现用户管理系统
  • 鸿蒙学习——开发中遇到的问题记录
  • Windows VMWare Centos Docker部署Springboot + mybatis + MySql应用
  • Embeddings模型
  • IOday2--7.1
  • 工作中常用的Git操作命令(一)
  • 电脑键盘不能打字了怎么解决 查看恢复方法
  • Wisdom SSH 与宝塔面板:深度对比剖析
  • P1312 [NOIP 2011 提高组] Mayan 游戏
  • 将POD指定具体机器上运行
  • ip网络基础
  • 睿抗-2025年江西省第三题
  • python+uniapp基于微信小程序的流浪动物救助领养系统nodejs+java