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,一经查实,立即删除!

相关文章

java基础教程(2)-Java基本数据类型

一个Java程序的基本结构&#xff1a; public class DemoTest {public static void main(String[] args) {// 打印一句话System.out.println("hello...");} }以上程序功能是实现打印一句话到控制台输出&#xff1b;这是一个基本的java结构&#xff0c;所有java程序都…

【数据结构】 单向链表的实现

单向链表是数据结构中的一种&#xff0c;它由节点组成&#xff0c;每个节点包含两个部分&#xff1a;数据域和指针域。数据域用于存储节点的值&#xff0c;指针域则用于指向下一个节点。单向链表的特点是只能从头节点开始遍历到尾节点&#xff0c;不能反向遍历。 1 单向链表的…

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

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

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

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

docker-002常用命令

启动类命令 启动systemctl start docker停止systemctl stop docker重启systemctl restart docker查看状态systemctl status docker开机启动systemctl enable docker概要docker info总体帮助文档docker --help命令帮助文档docker 具体命令 --help镜像命令 查看主机上的镜像 命令…

基于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个…

CSS继承、层叠和特殊性

继承性 CSS样式的相互传递&#xff0c;也就是说CSS内部标签拥有CSS外部标签的某些样式。我们可以利用CSS的继承性先把网页中具有相同&#xff0c;可继承的样式提取出来&#xff0c;然后进行全局中定义&#xff0c;利用继承属性影响整个页面的样式。 CSS中不可以继承的属性 1…

(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;…

L1-039 古风排版--Python

中国的古人写文字&#xff0c;是从右向左竖向排版的。本题就请你编写程序&#xff0c;把一段文字按古风排版。 输入格式&#xff1a; 输入在第一行给出一个正整数N&#xff08;<100&#xff09;&#xff0c;是每一列的字符数。第二行给出一个长度不超过1000的非空字符串&a…

【QT进阶】Qt http编程之http与https简单介绍

往期回顾 【QT进阶】Qt Web混合编程之html、 js的简单交互-CSDN博客 【QT进阶】Qt Web混合编程之使用ECharts显示各类折线图等-CSDN博客【QT进阶】Qt Web混合编程之实现ECharts数据交互动态修改-CSDN博客 【QT进阶】Qt http编程之http与https简单介绍 一、什么是http与https …

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

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

ThreadLocal 实战使用详解

ThreadLocal 知识储备传送门&#xff1a; ThreadLocal 原理及源码详解 ThreadLocal 内存泄漏和常见问题详解 什么是ThreadLocal&#xff1f; ThreadLocal 是一种提供线程本地变量&#xff08;也称为线程局部变量&#xff09;的类&#xff0c;这种变量确保了在不同的线程中访…

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;就是…