threejs中模型自定义路线移动

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>

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对整threeJS体系进行全面剖析。整理出全面的教学大纲,涵盖内容面非常广。此教学版本为threeJS107版本。关于版本不建议大家使用低于90的版本学习。以下是课程目录1-ThreeJS概览(基本图形简介,什么是点线面如何绘制点线面,什么是材质,什么是几何体,什么是相机,什么是渲染器,什么是场景)2-相机和渲染器(详解相机类型,渲染器如何使用,针对不同场景怎么用,怎么调效果,怎么渲染,怎么输出画布,如何解决透明问题等等)3-创建平面几何(常见的几何体如何使用,如何使用简单的几何体绘制出自定义自己想要的几何体,关于几何体的性能剖析,如何解决性能,几何体的渲染原理)4-高级图形算法常见库(求直线的斜率  计算线段与圆的交点 计算线段的长度 判断折线是否在多边形内 等等)5-sprite精灵(怎么让一个图标永远朝向屏幕,精灵的属性,精灵材质原理等,广告提示框必用)6-骨骼游戏动画(什么是模型动画,常见游戏案例,如何让人头进行各种攻击动作)7-3d模型加载(常见模型格式,如何渲染不同格式,不同格式的特点,什么格式性能优越,模型渲染异常,贴图不显示等问题详解)8-高阶动态纹理(你所不知道的纹理用法,我说你不知道,你肯定不知道)9-漫游轨迹以及其动画路径(怎么绘制贝塞尔曲线,如何使用曲线上的路径,跟随路径移动的原理,相机如何运动,物体如何运动)10-着色器(什么是着色器。初识着色器基础,着色器材质怎么用,怎么使用着色器库)11-常见渲染以及透明度问题12-对象拾取以及拖拽(3d世界里面如何拖拽物体,拖拽的原理,mousemove mouseon等的事件效果)13-世界坐标以及组的问题(什么是相对坐标,什么是世界坐标,什么是当前坐标,怎么转化父子坐标系,组的优化,为什么用组,组的优势)14-指定对象旋转心(什么是物体的几何体心,如何改变心,如何绕轴转动)15-层级对象渲染(多个场景一键切换,切换的优势,针对大项目的用法)16-拓展了解系列(不定期不断更新案例,各种酷炫效果bloom,halo等,以及各种3d图表,粒子案例等,不断构建你的3d实践能力)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值