THREEJS 使用CatmullRomCurve3实现汽车模型沿着指定轨迹移动

效果预览

在这里插入图片描述

准备所需资源

在这里插入图片描述

搭建场景环境

 const container = document.querySelector("#box_bim");// 创建摄像机camera = new THREE.PerspectiveCamera(50,window.innerWidth / window.innerHeight,0.1,1000);// camera.position.set(500, 500, 500);// 调整近裁减值camera.near = 0.1; // 根据需要调整这个值// 调整远裁减值camera.far = 100000; // 根据需要调整这个值// 更新相机投影矩阵(如果使用了透视投影)camera.updateProjectionMatrix();// 创建场景scene = new THREE.Scene();renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);renderer.shadowMap.enabled = truecontainer.appendChild(renderer.domElement);//辅助观察的坐标系const axesHelper = new THREE.AxesHelper(100);scene.add(axesHelper);const environment = new RoomEnvironment();
const pmremGenerator = new THREE.PMREMGenerator(renderer);scene.background = new THREE.Color(0x000000); //背景色scene.environment = pmremGenerator.fromScene(environment).texture;// 如果你使用的是 THREE.SpotLight(光束光源),可以通过以下方式设置光束的范围:const spotLight = new THREE.SpotLight(0xFFFFFF, 1, 100);spotLight.position.set(50, 50, 50);spotLight.angle = Math.PI / 4; // 光束的角度spotLight.penumbra = 0.05; // 光束边缘的模糊度spotLight.decay = 2; // 光强随距离的减少速度scene.add(spotLight);labelRenderer = new CSS2DRenderer();labelRenderer.setSize(window.innerWidth, window.innerHeight);labelRenderer.domElement.style.position = "absolute";labelRenderer.domElement.style.top = "0px";container.appendChild(labelRenderer.domElement);controls = new OrbitControls(camera, labelRenderer.domElement); //控制图层,添加相机控件controls.enableDamping = true;// controls.minDistance = 1;// controls.maxDistance = 10;controls.target.set(0, 0.5, 0);controls.autoRotate = falsecontrols.autoRotateSpeed =0.5controls.update();

添加模型

使用的是gltf类型的模型

        // 实例化加载器g1tfconst gltfLoader = new GLTFLoader();// 实例化加较器draco -- 为了解决大型模型经过压缩无法直接加载的问题const dracoloader = new DRACOLoader();dracoloader.setDecoderPath("./draco/");// 加载第一个模型 - 人gltfLoader.setDRACOLoader(dracoloader);gltfLoader.load("./model/people.gltf",(gltf) =>{// 设置模型大小gltf.scene.scale.set(0.2, 0.2, 0.2);gltf.scene.position.set(200,0,0)//调整人位置,使得车模型在小区模型的地面上people = gltf.scenescene.add(gltf.scene);})// 加载第二个模型 - 车辆gltfLoader.load("./model/car.gltf",(gltf) =>{gltf.scene.scale.set(0.2,0.2,0.2);gltf.scene.position.set(100,0,0)//调整车辆位置,使得车模型在小区模型的地面上car =  gltf.scenescene.add(gltf.scene); })// 加载第三个模型 - 小区gltfLoader.load("./model/district.gltf",(gltf) =>{gltf.scene.scale.set(0.08, 0.08, 0.08); // 小区模型太大,需要缩小gltf.scene.position.set(100,238,500)//调整车辆位置,使得车模型在小区模型的地面上gltf.scene.rotation.y  = -Math.PI / 13;//旋转模型,使得坐标轴与小区的房屋平行便于计算轨迹向量scene.add(gltf.scene);})

增加运动轨迹

 // 创建轨迹 - 车辆的移动轨迹spline = new THREE.CatmullRomCurve3([new THREE.Vector3(100,0,0), new THREE.Vector3(100,0,30), new THREE.Vector3(100,0,60), new THREE.Vector3(100,0,90), new THREE.Vector3(100,0,120), new THREE.Vector3(100,0,150), new THREE.Vector3(100,0,180), new THREE.Vector3(100,0,210), new THREE.Vector3(100,0,240), new THREE.Vector3(100,0,270), new THREE.Vector3(100,0,300), new THREE.Vector3(110,0,300), new THREE.Vector3(130,0,300), new THREE.Vector3(150,0,300), new THREE.Vector3(170,0,300), new THREE.Vector3(190,0,300), new THREE.Vector3(210,0,300), new THREE.Vector3(290,0,300), new THREE.Vector3(500,0,300), new THREE.Vector3(800,0,300), new THREE.Vector3(900,0,300), new THREE.Vector3(900,0,290), new THREE.Vector3(900,0,280), new THREE.Vector3(900,0,270), new THREE.Vector3(900,0,260), new THREE.Vector3(900,0,250), new THREE.Vector3(900,0,170), new THREE.Vector3(900,0,120), new THREE.Vector3(900,0,90), new THREE.Vector3(900,0,60), new THREE.Vector3(900,0,30), new THREE.Vector3(900,0,-30), new THREE.Vector3(900,0,-60), new THREE.Vector3(900,0,-90), new THREE.Vector3(800,0,-90), new THREE.Vector3(100,0,-90), ]);spline.curveType = 'catmullrom'spline.closed = true //设置是否闭环spline.tension = 0.5 //设置线的张力,0为无弧度折线// 为曲线添加材质在场景中显示出来,方便看到轨迹线const points = spline.getPoints(50) // 50等分获取曲线点const geometry = new THREE.BufferGeometry().setFromPoints(points);const material = new THREE.LineBasicMaterial({ color: 0x000000 });// Create the final object to add to the sceneconst curveObject = new THREE.Line(geometry, material);scene.add(curveObject) // 添加到场景中

使物体沿着轨迹移动

  // 创建渲染函数let progress = 0; // 物体运动时在运动路径的初始位置,范围0~1const velocity = 0.0008; // 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率// 物体沿线移动方法function moveOnCurve() {if (spline == null || car == null) {console.log("Loading")} else {if (progress <= 1 - velocity) {const point = spline.getPointAt(progress); //获取样条曲线指定点坐标const pointBox = spline.getPointAt(progress + velocity); //获取样条曲线指定点坐标if (point && pointBox) {car.position.set(point.x, point.y, point.z);var targetPos = pointBox   //目标位置点var offsetAngle = 0 //目标移动时的朝向偏移// //以下代码在多段路径时可重复执行var mtx = new THREE.Matrix4()  //创建一个4维矩阵// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。mtx.lookAt(car.position, targetPos, car.up) //设置朝向mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)))var toRot = new THREE.Quaternion().setFromRotationMatrix(mtx)  //计算出需要进行旋转的四元数值car.quaternion.slerp(toRot, 0.2)}progress += velocity;} else {progress = 0;}}};

参考链接

Three.js学习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/1043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入剖析图像平滑与噪声滤波

噪声 在数字图像处理中&#xff0c;噪声是指在图像中引入的不希望的随机或无意义的信号。它是由于图像采集、传输、存储或处理过程中的各种因素引起的。 噪声会导致图像质量下降&#xff0c;使图像失真或降低细节的清晰度。它通常表现为图像中随机分布的亮度或颜色变化&#…

面试不慌张:一文读懂FactoryBean的实现原理

大家好&#xff0c;我是石头~ 在深入探讨Spring框架内部机制时&#xff0c;FactoryBean无疑是一个关键角色&#xff0c;也是面试中经常出现的熟悉面孔。 不同于普通Java Bean&#xff0c;FactoryBean是一种特殊的Bean类型&#xff0c;它的存在并非为了提供业务逻辑&#xff0c;…

基于Springboot的小区物业管理系统

基于SpringbootVue的小区物业管理系统的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 用户管理 员工管理 业主信息管理 费用信息管理 楼房信息管理 保修信息…

【原创教程】海为PLC与RS-WS-ETH-6传感器的MUDBUS_TCP通讯

一、关于RS-WS-ETH-6传感器的准备工作 要完成MODBUS_TCP通讯,我们必须要知道设备的IP地址如何分配,只有PLC和设备的IP在同一网段上,才能建立通讯。然后还要选择TCP的工作模式,来建立设备端和PC端的端口号。接下来了解设备的报文格式,方便之后发送报文完成数据交互。 1、…

自定义Blazor单文件Web程序端口

#接 上篇 Mysql快速迁移版的制作过程# 上一篇《Mysql8快速迁移版的制作过程》完成了快速迁移的数据库的准备&#xff0c;今天接着讲基于Blazor的Web程序快速迁移版的制作。 单文件发布的难点不在发布而是因为程序系统默认给了个5001的端口&#xff0c;而是如何能够让用户自定…

AOP基础-动态代理

文章目录 1.动态代理1.需求分析2.动态代理的核心3.代码实例1.Vehicle.java2.Car.java3.Ship.java4.VehicleProxyProvider.java(动态代理模板)5.测试使用 2.动态代理深入—横切关注点1.需求分析2.四个横切关注点3.代码实例1.Cal.java2.CalImpl.java3.VehicleProxyProvider02.jav…

0-1背包问题:贪心算法与动态规划的比较

0-1背包问题&#xff1a;贪心算法与动态规划的比较 1. 问题描述2. 贪心算法2.1 贪心策略2.2 伪代码 3. 动态规划3.1 动态规划策略3.2 伪代码 4. C语言实现5. 算法分析6. 结论7. 参考文献 1. 问题描述 0-1背包问题是组合优化中的一个经典问题。假设有一个小偷在抢劫时发现了n个…

(C语言)sscanf 与 sprintf详解

目录 1.sprintf函数详解 2. sscanf函数详解 1.sprintf函数详解 头文件&#xff1a;stdio.h 作用&#xff1a;将格式化的数据写入字符串里&#xff0c;也就是将格式化的数据转变为字符串。 演示&#xff1a; #include <stdio.h> struct S {char name[10];int height;…

NX二次开发——矩形排料5(基于最低水平线+遗传算法排料策略实现)

目录 一、概述 二、知识回顾 2.1适应度函数的确定 2.2基因编码 2.3遗传算法复制&#xff08;选择&#xff09; 2.4遗传算法交叉操作 通过交叉操作可以增加种群个体的多样性&#xff0c;既可以产生更多的优秀解。下面通过顺序编码方法进行改进&#xff08;网上有很…

vue3:树的默认勾选和全选、取消全选

实现的功能&#xff0c;上面有个选择框&#xff0c;当选中全部时&#xff0c;下方树被全选 代码&#xff1a; <template><div><el-select v-model"selectAll" style"margin-bottom: 10px;" change"handleSelectAllChange">&…

electron打包dist为可执行程序后记【electron-quick-start】

文章目录 目录 文章目录 前言 一、直接看效果 二、实现步骤 1.准备dist文件夹 2.NVM管理node版本 3.准备electron容器并npm run start 4.封装成可执行程序 1.手动下载electron对应版本的zip文件&#xff0c;解决打包缓慢问题 2.安装packager 3.配置打包命令执行内容…

嵌入式linux中利用QT控制蜂鸣器方法

大家好,今天给大家分享一下,如何控制开发板上的蜂鸣器。 第一:开发板原理图 从原理图中可以得出,当引脚输出低电平的时候,对应的蜂鸣器发出响声。 第二:QT代码详细实现 设置一个按钮,点击即可控制BEEP状态发生反转。 #ifndef MAINWINDOW_H #define MAINWINDOW_H#in…

华为鸿蒙生态,威力估计被很多人低估了……

华为鸿蒙生态&#xff0c;威力估计被很多人低估了&#xff01;华为的鸿蒙千帆计划快成了&#xff0c;微信的加盟让计划就基本没问题了。 最近华为公布原生鸿蒙APP进度&#xff0c;在TOP5000应用里面&#xff0c;已经有4000支持了&#xff0c;不是已经开发完成&#xff0c;就是…

Electron+Vue3整合 - 开发时状态整合

说明 本文介绍一下 Electron Vue3 的整合的基本操作。实现的效果是 &#xff1a; 1、一个正常的Vue3项目&#xff1b; 2、整合加入 Electron 框架 &#xff1a;开发时 Electron 加载的是开发的vue项目&#xff1b;步骤一&#xff1a;创建vue3项目 常规操作&#xff0c;不再赘…

(C语言)fscanf与fprintf函数详解

目录 1 fprintf详解 1.1 向文件流中输入数据 1.2 向标准输入流写数据 2. fscanf函数详解 2.1 从文件中读取格式化数据 2.2 从标准输入流中读取格式化数据 1 fprintf详解 头文件&#xff1a;stdio.h 该函数和printf的参数特别像&#xff0c;只是多了一个参数stream&#…

删除word中下划线的内容

当试卷的题目直接含答案&#xff0c;不利用我们刷题。这时如果能够把下划线的内容删掉&#xff0c;那么将有利于我们复习。 删除下划线内容的具体做法&#xff1a; ①按ctrl H ②点格式下面的字体 ③选择下划线线型中的_____ ④勾选使用通配符并在查找内容中输入"?&qu…

增强现实(AR)开发框架

增强现实&#xff08;AR&#xff09;开发框架为开发者提供了构建AR应用程序所需的基本工具和功能。它们通常包括3D引擎、场景图、输入系统、音频系统和网络功能。以下是一些流行的AR开发框架。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流…

【C语言】贪吃蛇项目(2)- 实现代码详解

文章目录 前言一、游戏开始界面设计首先 - 打印环境界面其次 - 游戏地图、蛇身及食物的设计1、地图2、蛇身设置及打印3、食物 二、游戏运行环节蛇的上下左右移动等功能蛇的移动 三、结束游戏代码 前言 在笔者的前一篇博客中详细记载了贪吃蛇项目所需的一些必备知识以及我们进行…

MySQL面试题 3

问题1&#xff1a;char、varchar的区别是什么&#xff1f; varchar是变长而char的长度是固定的。如果你的内容是固定大小的&#xff0c;你会得到更好的性能。 问题2: TRUNCATE和DELETE的区别是什么&#xff1f; DELETE命令从一个表中删除某一行&#xff0c;或多行&#xff0…

上位机图像处理和嵌入式模块部署(树莓派4b实现动态插件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 和上位机一样&#xff0c;我们的智能硬件如果想应用到更多的场景&#xff0c;那么势必需要实现更多的算法。这些算法和算法之间最好是松散耦合的插…