threejs中模型自定义路线移动

news2024/11/25 13:19:51

threejs中模型自定义路线移动

生命不息,学习不止
基于r95Threejs版本
此例子中:包括背景设置:天空之盒。
模型的引用:小车和整体 glb模型引用
路线设置(因线line2无法设置宽度,所以选择了用管道,当然也可用点成面,看各自喜好):管道引用图片/颜色。
显示:标签
综合处理:比如缩放参数、指定模型闪烁、多个模型同时动态移动、移除场景等
具体效果如图

在这里插入图片描述
部分代码如下:如有需要完整代码,可私聊

<!DOCTYPE html>
<html>
	<head>
		<title>Threejs中寻路导航</title>
		<style>
			body {
				margin: 0;
				overflow: hidden;
			}
			.title {
				display: flex;
				align-items: center;
				justify-content: center;
				padding: 3px; 
				font-size: 18px;
				color: rgb(0, 255, 255);
				background: url(/static/scrap/assets/infoPg.png) no-repeat;
				background-size: cover;
				/* background-color: #ffff00; */
			}
		</style>
	</head>
	<body>
		<div id="dom">
		</div>
	
		<script type="text/javascript">
			var camera;//相机
			var renderer;//渲染器
			var carMovePath=[];//路径坐标
			var carRoute=[];//路线纹理
			var meshArr=[];//加载的小车模型
			var shperePathIndex=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];//路线索引
			var scene;//场景
			var labelObj=[];//场景中的标签
			var parkingdiv=[];//标签div
			var labelRenderer;//标签渲染器
			var material_yellow;//黄色材质--停车位闪烁用
			var material_hyaline; //蓝色材质--停车位闪烁用
			var cube12;
			let circle_n = 0; 
			var model; //场景整体模型
			var objectArr = []; //所有模型对象的集合,export导出用于射线拾取
			var multiple_z=1.5;//z(宽)值扩大的倍数
			var multiple_x=1;//x(长)值扩大的倍数
			var multiple_y=2;//y(高)值扩大的倍数
			function init() {
		
				// 创建一个场景,它将包含我们所有的元素,如物体,相机和灯光。
				scene = new THREE.Scene();
				var urls = [
				   './assets/6/posx.jpg',
					'./assets/6/negx.jpg',
					'./assets/6/posy.jpg',
					'./assets/6/negy.jpg',
					'./assets/6/posz.jpg',
					'./assets/6/negz.jpg'
				];
 				var cubeLoader = new THREE.CubeTextureLoader();
				scene.background = cubeLoader.load(urls);
                 
                	// 创建一个摄像机,它定义了我们正在看的地方
				camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
				// 将摄像机对准场景的中心
				camera.position.x = -1;
				camera.position.y = 40;
				camera.position.z = 40;
				camera.lookAt(scene.position);
				var orbit = new THREE.OrbitControls(camera);
				// 创建一个黄色的材质  
				material_yellow = new THREE.MeshLambertMaterial({color:0xFFFFFF}); 
				material_hyaline = new THREE.MeshBasicMaterial({
						color: 0x005577, //颜色材质
						transparent: true,//开启透明
						opacity: 0.5 //设置透明度
			    });

				var loader = new THREE.GLTFLoader();
				model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景
			
				loader.load("/static/scrap/mode/plane.glb", function (gltf) { //gltf加载成功后返回一个对象			
				 //   gltf.scene.getObjectByName("electricalBuilding").material=material_hyaline;
					model.add(gltf.scene);
					// 设置平面位置并旋转
					model.position.y =0.2; 
				    model.position.x = 0;
					model.position.z = 0; 
					//model.scale.set(1, 1, 1.5);
					model.scale.z=multiple_z;
					model.scale.x=multiple_x;
					model.scale.y=multiple_y;
				
				})
				scene.add(model);//将model.js中的模型放入场景
			     
                function buildName(coordinate,buildName,title){
					//设置标签
					var build = document.createElement('div');
					build.className = 'title';
					build.textContent =title;
					var buildMesh = new THREE.CSS2DObject(build);
					buildMesh.name=buildName;
					buildMesh.position.x =coordinate.x*multiple_x;  
				    buildMesh.position.y =2*multiple_y;
					buildMesh.position.z =coordinate.z*multiple_z;
					//labelObj.name="labelObj"+parkingNum;
					scene.add(buildMesh);
					buildMesh.element.style.visibility = 'visible';//显示标签  
				}
               

				// 创建一个渲染器并设置大小,WebGLRenderer将会使用电脑显卡来渲染场景
				renderer = new THREE.WebGLRenderer({
					antialias: true, //开启反锯齿,消除混叠、抗图像折叠有损等
					alpha: true,
				});
				renderer.setPixelRatio(window.devicePixelRatio); //设置设备像素比率,防止Canvas画布输出模糊。
				renderer.setSize(window.innerWidth, window.innerHeight);
				// 设置three.js背景颜色 和雾化颜色相配   0x005577
				renderer.setClearColor(0xa0a0a0, 1);
				//背景颜色透明化
				renderer.setClearAlpha(0);
				//解决加载gltf格式模型纹理贴图和原图不一样问题
				renderer.outputEncoding = THREE.sRGBEncoding; 
				// scene.add(new THREE.AmbientLight(0x666666));
				/**
				* 光源设置
				*/
				// 平行光1
				var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
				directionalLight.position.set(0, 20,-20);
				scene.add(directionalLight);
				// 平行光2
				var directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5);
				directionalLight2.position.set(-400, -200, -300);
				scene.add(directionalLight2);
				//环境光
				var ambientLight = new THREE.AmbientLight("#ffffff", 1);
				scene.add(ambientLight);
 
				// 在屏幕上显示坐标轴  
				// var axes = new THREE.AxisHelper(100);
				// scene.add(axes);
                     
				//将平面添加到场景中 
				var plane = createPlaneGeometryBasicMaterial();
				scene.add(plane);
	
				// 创建一个CSS2渲染器CSS2DRenderer
				labelRenderer = new THREE.CSS2DRenderer();
				labelRenderer.setSize(window.innerWidth, window.innerHeight);
				labelRenderer.domElement.style.position = 'absolute';
				// 相对标签原来位置偏移
				labelRenderer.domElement.style.top = '0';//信息弹窗界面高度一半
				labelRenderer.domElement.style.left = '0';//信息弹窗界面宽度一半
				// 设置.pointerEvents=none,以免模型标签HTML元素遮挡鼠标选择场景模型
				labelRenderer.domElement.style.pointerEvents = 'none';
				document.body.appendChild(labelRenderer.domElement);


				// 创建小车模型
				function createModels(parkingNum,carName) {
					//   let axes = new THREE.AxesHelper(6000);
					//   this.scene.add(axes);
					//使用指定的点创建一条平滑的三维样条曲线当做小车运动路径
					var point_scale_y=1;
					if(multiple_y>1){
						point_scale_y=multiple_y/10+1;  
					}
					carMovePath[parkingNum] = new THREE.CatmullRomCurve3(pointMap[parkingNum-1]);
					for (var i = 0; i < carMovePath[parkingNum].points.length; i++) {  
						var point = carMovePath[parkingNum].points[i];  
						point.x *= multiple_x;
						point.y *= point_scale_y;
						point.z *= multiple_z; 
						carMovePath[parkingNum][i] = point; 
					}
					carMovePath[parkingNum].curveType = 'catmullrom';//定义catmullrom的张力
					carMovePath[parkingNum].closed = false; //设置是否闭环
					carMovePath[parkingNum].tension=0;//设置线的张力,0为无弧度折线
					//参考路径上取1000个点,可以将模型安置在某个点位上
					const  pathPoints = carMovePath[parkingNum].getPoints(1000);

					// 引入三维模型(glb或者gltf格式)
					const loaders = new THREE.GLTFLoader();
					
					meshArr[parkingNum]=null;
					loaders.load(`/static/scrap/mode/car.glb`, (glb) => {
					//	meshArr[0] = glb.scene.children[0].children[0];
					    meshArr[parkingNum] = glb.scene.children[0];
						//这里就是将模型安置在i*333这个点位上
						meshArr[parkingNum].position.set(
							pathPoints[0].x, 
					        pathPoints[0].y,
					        pathPoints[0].z
						);
						//meshArr[0].rotation.y= 40 * (Math.PI / 180);
						//设置模型大小
						//meshArr[0].scale.set(0.001, 0.001, 0.001);
						meshArr[parkingNum].scale.set(0.6, 0.6, 0.6);
						scene.add(meshArr[parkingNum]);

					});
					
					//设置路线指引
					var tubeGeometry = new THREE.TubeGeometry(carMovePath[parkingNum], 200, 0.1, 300, false);
					var textureLoader = new THREE.TextureLoader();
					var texture = textureLoader.load('/static/scrap/assets/2.png');
				
					// 设置阵列模式 RepeatWrapping
					// texture.wrapS = THREE.RepeatWrapping
					texture.wrapT = THREE.RepeatWrapping
					// 设置x方向的重复数(沿着管道路径方向)
					// 设置y方向的重复数(环绕管道方向)
					texture.repeat.x = 10;
					texture.repeat.y = 4;
					// 设置管道纹理偏移数,便于对中
					texture.offset.y = 0.5;
					var tubeMaterial = new THREE.MeshPhongMaterial({
						//map: texture,
						color: 0xff0000,
						transparent: true
					});
					carRoute[parkingNum] = new THREE.Mesh(tubeGeometry, tubeMaterial);
					carRoute[parkingNum].name="carRoute"+parkingNum;
					carRoute[parkingNum].position.y = -2;
					//mesh.rotateZ(3.14);
					carRoute[parkingNum].scale.set(1, 1, 1);
					// 使用加减法可以设置不同的运动方向
					setInterval(() => {
						if(texture.offset.x<=-10){
							texture.offset.x =0
						}else{
							texture.offset.x -= 0.0036
						}
						
					})
					scene.add(carRoute[parkingNum])          
					
					//设置标签
					parkingdiv[parkingNum] = document.createElement('div');
					parkingdiv[parkingNum] .className = 'title';
					parkingdiv[parkingNum] .textContent =carName;
					labelObj[parkingNum] = new THREE.CSS2DObject(parkingdiv[parkingNum]);
					labelObj[parkingNum].position.x =pathPoints[0].x;  
					labelObj[parkingNum].position.y =pathPoints[0].y;
					labelObj[parkingNum].position.z =pathPoints[0].z;
					//labelObj.name="labelObj"+parkingNum;
					scene.add(labelObj[parkingNum]);
					labelObj[parkingNum].element.style.visibility = 'visible';//显示标签    
					//设置对应的停车位闪烁
					if (scene.getObjectByName("parking"+parkingNum) !=null) {
						scene.getObjectByName("parking"+parkingNum).material = shaderMaterial;
					}  		
				}

				/**
				* 呼吸灯 添加渲染通道
				*/
				var shaderMaterial = new THREE.ShaderMaterial({  
					uniforms: {  
						time: { value: 1.0 },  
						color1: { value: new THREE.Color(0xFFFFFF) },  
						color2: { value: new THREE.Color(0x005577) }  
					},  
					vertexShader: [  
						'varying vec3 vNormal;',  
						'void main() {',  
							'vNormal = normalize(normalMatrix * normal);',  
							'gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);',  
						'}'  
					].join('\n'),  
					fragmentShader: [  
						'uniform float time;',  
						'uniform vec3 color1;',  
						'uniform vec3 color2;',  
						'varying vec3 vNormal;',  
						'void main() {',  
							'float intensity = sin(time + vNormal.z);',  
							'gl_FragColor = vec4(mix(color1, color2, intensity), 1.0);',  
						'}'  
					].join('\n')  
				});

				// 将呈现器的输出添加到HTML元素
				document.getElementById("dom").appendChild(renderer.domElement);
				
			
				// 创建一个地面
				function createPlaneGeometryBasicMaterial() {
					var textureLoader = new THREE.TextureLoader();
					var cubeMaterial = new THREE.MeshStandardMaterial({
						map: textureLoader.load("/static/scrap/assets/cd.jpg"),
					});
					cubeMaterial.map.wrapS = THREE.RepeatWrapping;
					cubeMaterial.map.wrapT = THREE.RepeatWrapping;
					cubeMaterial.map.repeat.set(8, 8)
					// 创建地平面并设置大小
					var planeGeometry = new THREE.PlaneGeometry(200, 200);
					var plane = new THREE.Mesh(planeGeometry, cubeMaterial);
 
					// 设置平面位置并旋转
					plane.rotation.x = -0.5 * Math.PI;
					plane.position.x = 0;
					plane.position.z = 0;
					return plane;
				}
                
				//小车路径索引更新
			
				
				// 启动动画
				renderScene();
				
				//渲染
				function renderScene() {
					orbit.update();		
					labelRenderer.render(scene, camera);	
					shaderMaterial.uniforms.time.value += 0.07; // 你可以根据需要调整这个值  
				    // 使用requestAnimationFrame函数进行渲染
				    requestAnimationFrame(renderScene);
				    renderer.render(scene, camera);
				}
				// 渲染的场景
				renderer.render(scene, camera);

		
			}
			window.onload = init;
			
			// 随着窗体的变化修改场景
			function onResize() {
			    camera.aspect = window.innerWidth / window.innerHeight;
			    camera.updateProjectionMatrix();
			    renderer.setSize(window.innerWidth, window.innerHeight);
			}
			// 监听窗体调整大小事件
			window.addEventListener('resize', onResize,  { passive: false });
		
		</script>
	</body>
</html>

其中,还有一些不足,但作为一个例子,其中包含的还是比较全的。欢迎互相交流

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

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

相关文章

MySQL 索引介绍和最佳实践

目录 一、前言二、索引类型1.1 主键索引&#xff08;PRIMARY KEY&#xff09;1.2 唯一索引&#xff08;UNIQUE&#xff09;1.3 普通索引&#xff08;NORMAL&#xff09;1.3.1 单列普通索引1.3.2 单列前缀普通索引1.3.3 多列普通索引1.3.4 多列前缀普通索引 1.4 空间索引&#x…

商场做小程序商城的作用是什么?

商场是众多商家聚集在一起的购物公共场所&#xff0c;大商场也往往入驻着众多行业商家&#xff0c;是每个城市重要的组成部分。 随着互联网电商深入及客户消费行为改变&#xff0c;不少商场如今的客流量非常有限&#xff0c;甚至可以说是员工比客人多&#xff0c;这就导致撤店…

三相Vienna整流器电流畸变的抑制方法

该博客参考丁文龙的博士论文《低成本充电系统高性能多端口Vienna整流器关键控制策略研究》&#xff0c;他的博士论文深入浅出&#xff0c;分析透彻。感谢师妹Miss Young提供的技术指导&#xff0c;她是一位优秀的电力电子工程师&#xff0c;祝她事业顺利&#xff0c;身体健康。…

【教学类-06-06】20230905数字题目随便玩( 加减法、分合、比大小,纸张消耗)

背景需求&#xff1a; 3年前第一次设计加减法题目时&#xff0c;打印了一大堆加减法、数字分合、比大小的纸张。太多了&#xff0c;以至于三年后整理素材库&#xff0c;发现还有很多这样的纸片。这些20以内、50以内的题目难度大、题量多&#xff0c;完全不适合幼儿园孩子做&am…

Linux基础命令汇总

用户管理 su 切换用户&#xff1a;su 用户名 logname 显示当前用户的登录用户名&#xff1a;logname useradd 创建用户&#xff1a;useradd 用户名创建用户时指定用户的主组&#xff1a;useradd -g 组名 用户名 usermod 添加附属组&#xff1a;usermod -G 组…

基于 Python+DenseNet121 算法模型实现一个图像分类识别系统

项目展示 一、介绍 DenseNet&#xff08;Densely Connected Convolutional Networks&#xff09;是一种卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;2017年由Gao Huang等人提出。该网络的核心思想是密集连接&#xff0c;即每一层都接收其前面所有层的输出作为输…

CISSP学习笔记:安全脆弱性、威胁和对策

第九章 安全脆弱性、威胁和对策 9.1 评估和缓解安全脆弱性 9.1 硬件 处理器执行类型 多任务处理&#xff1a; 同时处理两个或更多任务多处理&#xff1a; 利用多个处理器完成一个应用程序的处理能力多程序设计&#xff1a;通过操作系统对单个处理器上的两个任务进行协调&…

AHH HackerHouse @Move大理站完美谢幕

Antalpha HackerHouse Move 大理站于2023年9月23日在面包树举办了Final DemoDay&#xff0c;这也代表着为期21天的 HackerHouse 活动完美谢幕。 自从9月3日开始&#xff0c;整整21天的共居时间里&#xff0c;我们从个体逐渐融汇成小团队&#xff0c;最终成为了一个紧密团结的大…

新手教程,蛋糕小程序的搭建流程一网打尽

作为一名新手&#xff0c;想要搭建一个蛋糕小程序可能会觉得有些困惑。但是&#xff0c;不用担心&#xff01;今天我将为大家详细介绍蛋糕小程序的搭建流程&#xff0c;并带大家一步步完成。 首先&#xff0c;我们需要登录乔拓云网的后台。在登录成功后&#xff0c;点击进入商城…

OCI 发布了容器运行时和镜像规范!

7 月 19 日是开放容器计划Open Container Initiative&#xff08;OCI&#xff09;的一个重要里程碑&#xff0c;OCI 发布了容器运行时和镜像规范的 1.0 版本&#xff0c;而 Docker 在这过去两年中一直充当着推动和引领的核心角色。 我们的目标是为社区、客户以及更广泛的容器行…

医疗小程序开发:技术门槛高?

随着移动互联网的普及&#xff0c;医疗行业也逐渐转向线上。医疗小程序开发成为了很多企业和医疗机构关注的焦点。但是&#xff0c;对于一些技术小白来说&#xff0c;可能会觉得医疗小程序开发技术门槛高&#xff0c;无从下手。实际上&#xff0c;使用乔拓云平台进入后台&#…

《Python趣味工具》——ppt的操作(刷题版)

前面我们对PPT进行了一定的操作&#xff0c;并将其中的文字提取到了word文档中。现在就让我们来刷几道题巩固巩固吧&#xff01; 文章目录 1. 查看PPT&#xff08;上&#xff09;2. 查看PPT&#xff08;中&#xff09;3. 查看PPT&#xff08;下&#xff09;4. PPT的页码5. 大学…

KUKA机器人通过3点法设置工作台基坐标系的具体方法

KUKA机器人通过3点法设置工作台基坐标系的具体方法 具体方法和步骤可参考以下内容: 进入主菜单界面,依次选择“投入运行”—“测量”—基坐标,选择“3点法”, 在系统弹出的基坐标编辑界面,给基座标编号为3,命名为table1,然后单击“继续”按钮,进行下一步操作, 在弹出的…

【论文极速读】Prompt Tuning——一种高效的LLM模型下游任务适配方式

【论文极速读】Prompt Tuning——一种高效的LLM模型下游任务适配方式 FesianXu 20230928 at Baidu Search Team 前言 Prompt Tuning是一种PEFT方法&#xff08;Parameter-Efficient FineTune&#xff09;&#xff0c;旨在以高效的方式对LLM模型进行下游任务适配&#xff0c;本…

车联网时代,能链车联凭什么成为“关键先生”?

又到国庆长假&#xff0c;许多人开启远途旅行&#xff0c;高速路上一如既往的拥堵。在密密麻麻的汽车中&#xff0c;新能源汽车变得越来越多。 事实上&#xff0c;新能源汽车的热潮&#xff0c;已经成为不可抵挡的趋势。据中国乘联会的最新数据&#xff0c;今年中国新能源乘用…

USB TypeC接口说明

USB TypeC 拥有诸多优点:双面可插不担心正反、可做USB/雷电高速传输载体,支持 PD快充、音频设备、HDMI传输、调试模式等诸多功能。 市面上的其他USB接口和充电接口在逐步被TypeC替代,可以预见的是,TypeC作为一种多兼容性接口,其未来会具有非常长的生命周期。 本文主要介…

Eclipse环境基于HDFS的API进行开发

文章目录 IOUtils方式读取文件1.文件准备2.下载安装Eclipse3.打开eclipse&#xff0c;新建java项目&#xff0c;添加关于hadoop的一些包4.包内新建类进行开发5.利用打包的方式生成java jar包6.验证代码正确性 其它问题&#xff1a;Exception in thread “main“ java.lang.Unsu…

TouchGFX界面开发 | 添加触摸屏驱动

使用STM32CubeMX移植TouchGFX 一文中介绍了如何用TouchGFX点亮屏幕&#xff0c;但是此时屏幕还没有触摸的功能。下面将介绍如何添加触摸屏驱动到TouchGFX中 一、STM32CubeMX配置 在使用STM32CubeMX移植TouchGFX 文中的STM32CubeMX配置基础上&#xff0c;再激活一个定时器&…

Pikachu靶场——XXE 漏洞

文章目录 1. XXE1.1 查看系统文件内容1.2 查看PHP源代码1.3 查看开放端口1.4 探测内网主机 1. XXE 漏洞描述 XXE&#xff08;XML External Entity&#xff09;攻击是一种利用XML解析器漏洞的攻击。在这种攻击中&#xff0c;攻击者通过在XML文件中插入恶意实体来触发解析器加载…

自然语言处理(NLP)学习之与HanLP的初相识

目录 前言 一、自然语言处理基本知识 1、NLP类别 2、核心任务 二、Hanlp简要介绍 三、Hanlp云服务能力 1、全新云原生2.x 2、Python api调用 3、Go api调用 4、Java api调用 四、Hanlp native服务 1、本地开发 总结 前言 在ChatGPT的滚滚浪潮下&#xff0c;也伴随着人工智…