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

网站版块模板大学生网站建设心得

网站版块模板,大学生网站建设心得,seo优化啥意思,ps做网站效果图制作过程Three.js 搭建3D隧道监测 Three.js 基础元素场景scene相机carema网络模型Mesh光源light渲染器renderer控制器controls 实现3d隧道监测基础实现道路实现隧道实现多个摄像头点击模型进行属性操作实现点击模型发光效果 性能监视器stats引入使用 总结完整代码 我们将通过three.js技… Three.js 搭建3D隧道监测 Three.js 基础元素场景scene相机carema网络模型Mesh光源light渲染器renderer控制器controls 实现3d隧道监测基础实现道路实现隧道实现多个摄像头点击模型进行属性操作实现点击模型发光效果 性能监视器stats引入使用 总结完整代码 我们将通过three.js技术打造3d隧道监测可视化项目隧道监测项目将涵盖照明风机的运行情况控制车道指示灯关闭情报板、火灾报警告警、消防安全、车行横洞、风向仪、隧道紧急逃生出口的控制以及事故模拟等那先来看看我们的初步成果因为作者也是在边学习边做的情况效果有些丑陋希望不要见笑three.js基础知识还是基本涵盖了入门还是很有参考价值的 Three.js 基础元素 我们将通过一个基本的three.js模板代码更好的概况我们的基础元素 import React, { useEffect } from react; import * as THREE from three; // eslint-disable-next-line import/extensions import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js;export default function ThreeVisual() {// 场景let scene;// 相机let camera;// 控制器let controls;// 网络模型let mesh;// 渲染器let renderer;// debugger属性const debugObject {light: {amlight: {color: 0xffffff,},directionalLight: {color: 0xffffff,position: {x: 0,y: 400,z: 1800,},},pointLight: {color: 0xff0000,position: {x: 0,y: 400,z: 1800,},},},};const sizes {width: window.innerWidth,height: window.innerHeight,};useEffect(() {// eslint-disable-next-line no-use-before-definethreeStart();}, []);const initThree () {const width document.getElementById(threeMain).clientWidth;const height document.getElementById(threeMain).clientHeight;renderer new THREE.WebGLRenderer({antialias: true,logarithmicDepthBuffer: true,});renderer.shadowMap.enabled true;renderer.setSize(width, height);document.getElementById(threeMain).appendChild(renderer.domElement);};const initCamera (width, height) {camera new THREE.PerspectiveCamera(45, width / height, 0.1, 10000);camera.position.x 0;camera.position.y 500;camera.position.z 1300;camera.up.x 0;camera.up.y 1;camera.up.z 0;camera.lookAt({x: 0,y: 0,z: 0,});// 创建相机视锥体辅助对象// const cameraPerspectiveHelper new THREE.CameraHelper(camera);// scene.add(cameraPerspectiveHelper);};const initScene () {scene new THREE.Scene();scene.background new THREE.Color(0xbfd1e5);};const initLight () {// 环境光const amlight new THREE.AmbientLight(debugObject.light.amlight.color);amlight.position.set(1000, 1000, 1000);scene.add(amlight);};const initObject () {const geometry new THREE.BoxGeometry(3000, 6, 2400);const material new THREE.MeshBasicMaterial({color: 0xcccccc});geometry.position new THREE.Vector3(0, 0, 0);mesh new THREE.Mesh(geometry, [material, material, material, material, material, material]);mesh.receiveShadow true; // cast投射方块投射阴影scene.add(mesh);}const initControl () {// 将renderer关联到container这个过程类似于获取canvas元素const pcanvas document.getElementById(threeMain);controls new OrbitControls(camera, pcanvas);// 如果使用animate方法时将此函数删除// controls.addEventListener( change, render );// 使动画循环使用时阻尼或自转 意思是否有惯性controls.enableDamping true;// 动态阻尼系数 就是鼠标拖拽旋转灵敏度// controls.dampingFactor 0.25;// 是否可以缩放controls.enableZoom true;// 是否自动旋转// controls.autoRotate true;controls.autoRotateSpeed 0.5;// 设置相机距离原点的最近距离// controls.minDistance 10;// 设置相机距离原点的最远距离controls.maxDistance 10000;// 是否开启右键拖拽controls.enablePan true;};function animation() {renderer.render(scene, camera);// mesh.rotateY(0.01);requestAnimationFrame(animation);}function initHelper() {const axesHelper new THREE.AxesHelper(3000);scene.add(axesHelper);}function threeStart() {initThree();initScene();initCamera(sizes.width, sizes.height);initHelper();initObject();initLight();initControl();animation();}return div idthreeMain style{{ width: 100vw, height: 100vh }} /; }场景scene 是一个三维空间相当于我们html中的body,所有节点的容器相当于一个空房间承载所有的物品所以我们定义一个全局变量scene。 初始化我们可以这样 const initScene () {scene new THREE.Scene();scene.background new THREE.Color(0xbfd1e5);};相机carema 打个比方就是你买了一个1万元的相机出门拍风景你总是想要抓住最美的风景那你便要调好相机最精确的位置、角度、焦距等相机看到的内容就是我们最终在屏幕上看到的内容。在这个例子中我们用的是像我们眼睛的透视相机PerspectiveCamera。 还有一个常用的相机是正交相机OrthographicCamera它看到的范围不会受距离影响 我们也定义了一个全局变量camera, 初始化我们可以这样 const initCamera (width, height) {camera new THREE.PerspectiveCamera(45, width / height, 0.1, 10000);camera.position.x 0;camera.position.y 500;camera.position.z 1300;camera.up.x 0;camera.up.y 1;camera.up.z 0;camera.lookAt({x: 0,y: 0,z: 0,});// 创建相机视锥体辅助对象// const cameraPerspectiveHelper new THREE.CameraHelper(camera);// scene.add(cameraPerspectiveHelper);};网络模型Mesh 在介绍它之前我们需要先了解点模型Points、线模型Line。点线面面就是Mesh模型。点模型Points、线模型Line、网格网格模型Mesh都是由几何体Geometry和材质Material构成。在这里就不过多研究点线面了我们最重要的知道的是一个网络模型就是一个物体穿上了衣服没有穿衣服的皇帝不会让别人揭穿和笑话但是我们的老板才是皇帝所以尽量给我们的模型套件衣服吧 同理定义一个全局变量mesh 初始化我们可以这样 const geometry new THREE.BoxGeometry(3000, 6, 2400); const material new THREE.MeshBasicMaterial({color: 0xcccccc}); geometry.position new THREE.Vector3(0, 0, 0); mesh new THREE.Mesh(geometry, [material, material, material, material, material, material]); mesh.receiveShadow true; // cast投射方块投射阴影 scene.add(mesh);光源light 没有光世界便是黑暗的同理假如没有光摄像机看不到任何东西。所以我们需要为我们的场景加上不同光照效果。我们先从最基础的环境光AmbientLight开始。环境光意思就是哪个角度、哪个位置的光照亮度强度都一样。因为光不需要重复使用所以我们没必要定义全局变量所以我们初始化可以这样 const initLight () {// 环境光const amlight new THREE.AmbientLight(debugObject.light.amlight.color);amlight.position.set(1000, 1000, 1000);scene.add(amlight); };渲染器renderer 就相当于现实生活中你带着相机现在去了一个美丽的地方你需要一个相片承载下这个美丽的景色对于threejs而言如果你需要这张相片就需要一个新的对象也就是WebGL渲染器WebGLRenderer把这些承载。 同理我们定义一个全局变量renderer初始化我们可以这样 renderer new THREE.WebGLRenderer({... //属性配置 });渲染器还需要补充几点就是如何和我们的dom节点关联起来 渲染器WebGLRenderer通过属性domElement可以获得渲染方法render()生成的Canvas画布domElement本质上就是一个HTML元素Canvas画布。我们也可以通过setSize()来设置尺寸。 定义一个html元素 return div idthreeMain style{{ width: 100vw, height: 100vh }} /;html元素和渲染器关联那就给div增加一个子节点(canvas) const initThree () {const width document.getElementById(threeMain).clientWidth;const height document.getElementById(threeMain).clientHeight;renderer new THREE.WebGLRenderer({... //属性配置});renderer.setSize(width, height); //设置画布宽高document.getElementById(threeMain).appendChild(renderer.domElement); // 把画布加入dom节点 };渲染器和我们的threejs元素关联 那渲染器渲染方法.render(),把我们的场景和相机记录进来了 renderer.render(scene, camera);控制器controls 就是相当于可以通过我们的键盘和鼠标来控制我们的场景使其有了交互功能控制器种类有很多但这里我们只说轨道控制器OrbitControls。它可以使得相机围绕目标进行轨道运动。打个比方地球围绕太阳一样运动。 同理我们定义一个全局变量controls初始化我们可以这样 controls new OrbitControls(camera, pcanvas);关联操作和属性介绍 const initControl () {// 将renderer关联到container这个过程类似于获取canvas元素const pcanvas document.getElementById(threeMain);controls new OrbitControls(camera, pcanvas);// 如果使用animate方法时将此函数删除// controls.addEventListener( change, render );// 使动画循环使用时阻尼或自转 意思是否有惯性controls.enableDamping true;// 动态阻尼系数 就是鼠标拖拽旋转灵敏度// controls.dampingFactor 0.25;// 是否可以缩放controls.enableZoom true;// 是否自动旋转// controls.autoRotate true;controls.autoRotateSpeed 0.5;// 设置相机距离原点的最近距离// controls.minDistance 10;// 设置相机距离原点的最远距离controls.maxDistance 10000;// 是否开启右键拖拽controls.enablePan true; };到此我们已经把threejs基础元素介绍的差不多了在这里还需要补充一些很容易遗漏的地方 动画和及时更新 function animation() {controls.update()renderer.render(scene, camera);// mesh.rotateY(0.01);requestAnimationFrame(animation); }补充一个知识点 requestAnimationFrame 实现3d隧道监测基础 实现道路 如图我们首先实现发光这部分。 这部分主要涉及的知识是给一个平面(plane)贴图具体的知识我在代码块相应位置已经标注。 // 图加载器 const loader new THREE.TextureLoader(); // 加载 const texture loader.load(/model/route.png, function(t) {// eslint-disable-next-line no-param-reassign,no-multi-assignt.wrapS t.wrapT THREE.RepeatWrapping; //是否重复渲染和css中的背景属性渲染方式很像t.repeat.set(1, 1); });// 平面 const geometryRoute new THREE.PlaneGeometry(1024, 2400); const materialRoute new THREE.MeshStandardMaterial({map: texture, // 使用纹理贴图side: THREE.BackSide, // 背面渲染 }); const plane new THREE.Mesh(geometryRoute, materialRoute); plane.receiveShadow true; plane.position.set(0, 8, 0); plane.rotateX(Math.PI / 2); scene.add(plane);实现隧道 现在我们实现发光这部分 这部分主要涉及的知识是引入一个obj模型并给模型贴上贴图(这里的材质是一个mtl) 补充知识点 OBJ是一种3D模型文件因此不包含动画、材质特性、贴图路径、动力学、粒子等信息 我们拿到一个隧道obj模型的文件打开看看里面是什么 mtl文件Material Library File是材质库文件描述的是物体的材质信息ASCII存储任何文本编辑器可以将其打开和编辑。同理我们也可以打开看看是个什么东西 从obj文件看出我们需要tunnelWall.mtl材质,从mtl文件看出我们需要suidao.jpg图片(需要和模型放在同一级)其实到这里我们还是回到了引入道路的那部分模型贴图环节。 但是还是有一些不同的地方的首先使用的加载器不同 const mtlLoader new MTLLoader(); const loader new OBJLoader(); // 在init函数中创建loader变量用于导入模型其次我们的模型是属于建模自己构造的可能你引入进来很大可能是加载不出来的所以你需要打印对象从中分析具体原因。 // 模型对象公共变量 const modelsObj {tunnelWall: {mtl: /model/tunnelWall.mtl,obj: /model/tunnelWall.obj,mesh: null,},camera: {mtl: /model/camera/摄像头方.mtl,obj: /model/camera/摄像头方.obj,mesh: null,}, }; mtlLoader.load(modelsObj.tunnelWall.mtl, material {material.preload();// 设置材质的透明度// mtl文件中的材质设置到obj加载器loader.setMaterials(material);loader.load(modelsObj.tunnelWall.obj, object {// 设置模型大小和中心点object.children[0].geometry.computeBoundingBox();object.children[0].geometry.center();modelsObj.tunnelWall.mesh object;scene.add(object);}); });实现多个摄像头 现在我们实现摄像头部分 这里其实和实现隧道大相径庭只不过我们是多个而隧道是单个。所以我们需要引入组(group)和克隆(clone)的概念。 知识点补充 组对象group相当于一个身体有胳膊、头、腿组成一个组。每个人组合可以再次分一个组。克隆clone:字面意思就是克隆一个一模一样的你。但是需要和copy分开。 // 加载摄像头模型 const loadCameraModel () {const mtlLoader new MTLLoader();const loader new OBJLoader(); // 在init函数中创建loader变量用于导入模型mtlLoader.load(modelsObj.camera.mtl, material {material.preload();// 设置材质的透明度// mtl文件中的材质设置到obj加载器loader.setMaterials(material);loader.load(modelsObj.camera.obj, object {console.log(object);// 设置模型大小object.children[0].geometry.computeBoundingBox();object.children[0].geometry.center();modelsObj.camera.mesh object;cloneCameraModel(4, 60, 180);cloneCameraModel(4, -200, 180);});}); }; // 克隆摄像头模型 const cloneCameraModel (cameraSize, lrInterval, baInterval) {const group new THREE.Group();for (let i 0; i cameraSize; i 1) {modelsObj[camera${i}] modelsObj.camera.mesh.clone();modelsObj[camera${i}].position.set(lrInterval, 180, baInterval * (i % 2 0 ? -i : i));modelsObj[camera${i}].scale.set(1, 1, 1);group.add(modelsObj[camera${i}])}scene.add(group); };点击模型进行属性操作 这块我们需要涉及的知识点是点击操作(Raycaster)、发光部分(效果合成器shader渲染使用)、debugger模式(gui) 首先我们实现对模型进行的点击我们需要使用raycaster 定义全局变量mouse初始化鼠标光线追踪。可以这样定义 // 获取鼠标坐标 处理点击某个模型的事件 const mouse new THREE.Vector2(); // 初始化一个2D坐标用于存储鼠标位置 const raycaster new THREE.Raycaster(); // 初始化光线追踪知识点补充 光线投射raycaster可以向特定方向投射光线并测试哪些对象与其相交由鼠标点击转为世界坐标的过程。就是把一个2d坐标转变成3d坐标的强大类 我们监听屏幕点击事件 const pcanvas document.getElementById(threeMain); // 监听点击事件,pcanvas pcanvas.addEventListener(click, e onmodelclick(e)); // 监听点击计算点击坐标屏幕坐标系转换成世界坐标系的过程。并赋值全局变量点击模型clickModel。 const onmodelclick event {console.log(event);// 获取鼠标点击位置mouse.x (event.clientX / sizes.width) * 2 - 1;mouse.y -(event.clientY / sizes.height) * 2 1;console.log(mouse);raycaster.setFromCamera(mouse, camera);const intersects raycaster.intersectObjects(scene.children); // 获取点击到的模型的数组从近到远排列// const worldPosition new THREE.Vector3(); // 初始化一个3D坐标用来记录模型的世界坐标if (intersects.length 0) {clickModel intersects[0].object; outlinePass.selectedObjects [];outlinePass.selectedObjects [clickModel];} };实现点击模型发光效果 threejs提供了一个扩展库EffectComposer.js,通过这个我们可以实现一些后期处理效果。所谓后期处理就像ps一样对threejs的渲染结果进行后期处理比如添加发光效果。我们结合高亮发光描边可以实现下图发光效果。 引入相关类 import { OutlinePass } from three/examples/jsm/postprocessing/OutlinePass; import { EffectComposer } from three/examples/jsm/postprocessing/EffectComposer; import { ShaderPass } from three/examples/jsm/postprocessing/ShaderPass; import { RenderPass } from three/examples/jsm/postprocessing/RenderPass; import { FXAAShader } from three/examples/jsm/shaders/FXAAShader; import { OutputPass } from three/examples/jsm/postprocessing/OutputPass;初始化三个全局变量 let composer; let effectFXAA; let outlinePass;赋值选中发光模型 const onmodelclick event { ...if (intersects.length 0) {outlinePass.selectedObjects [];outlinePass.selectedObjects [clickModel];} };初始化加载发光效果 // 效果合成器shader渲染使用 const initEffectComposer () {// 处理模型闪烁问题【优化展示网格闪烁】// const parameters { format: THREE.RGBAFormat };// const size renderer.getDrawingBufferSize(new THREE.Vector2());// const renderTarget new THREE.WebGLMultipleRenderTargets(size.width, size.height, parameters);composer new EffectComposer(renderer);const renderPass new RenderPass(scene, camera);composer.addPass(renderPass);outlinePass new OutlinePass(new THREE.Vector2(sizes.width, sizes.height), scene, camera);outlinePass.visibleEdgeColor.set(255, 255, 0);outlinePass.edgeStrength 1.0; // 边框的亮度outlinePass.edgeGlow 1; // 光晕[0,1]outlinePass.usePatternTexture false; // 是否使用父级的材质outlinePass.edgeThickness 1.0; // 边框宽度outlinePass.downSampleRatio 1; // 边框弯曲度composer.addPass(outlinePass);const outputPass new OutputPass();composer.addPass(outputPass);effectFXAA new ShaderPass(FXAAShader);effectFXAA.uniforms.resolution.value.set(1 / sizes.width, 1 / sizes.height);composer.addPass(effectFXAA); };渲染循环执行 function animation() {stats.update();renderer.render(scene, camera);composer.render();// mesh.rotateY(0.01);requestAnimationFrame(animation); }debugger模式 这节主要涉及gui并且补充一下阴影的知识。gui是一个图形用户界面工具,我们可以通过这个工具实现对属性进行动态的操作很方便。下面标红的就是我们的界面工具 我们通过增加点光源来举个例子。 首先我们初始化全局变量gui并且赋值 // debugger let gui; function initDebugger() {gui new GUI(); }定义全局变量debugObject需要改变的属性。 // debugger属性 const debugObject {light: {pointLight: {color: 0xff0000,position: {x: 0,y: 400,z: 1800,},},}, }; 定义点光源对点光源的位置和颜色属性动态切换 // 点光源 const pointLight new THREE.PointLight(debuggerPointLight.color, 1); pointLight.castShadow true; pointLight.position.set(100, 100, 300); scene.add(pointLight); const pointLightFolder lightFolder.addFolder(点光源); pointLightFolder.addColor(debuggerPointLight, color).onChange(function(value) {pointLight.color.set(value); }); // 点光源位置 pointLightFolder.add(debuggerPointLight.position, x, -1000, 1000).onChange(function(value) {pointLight.position.x value;pointLightHelper.update(); }); pointLightFolder.add(debuggerPointLight.position, y, -1000, 1000).onChange(function(value) {pointLight.position.y value;pointLightHelper.update(); }); pointLightFolder.add(debuggerPointLight.position, z, -1000, 1000).onChange(function(value) {pointLight.position.z value;pointLightHelper.update(); });实现效果如图 开启阴影 阴影渲染 renderer new THREE.WebGLRenderer({... }); renderer.shadowMap.enabled true;点光源投射光影 const pointLight new THREE.PointLight(debuggerPointLight.color, 1); pointLight.castShadow true;模型和道路接受阴影和投射阴影 plane.receiveShadow true;loader.load(modelsObj.tunnelWall.obj, object {object.traverse(obj {if (obj.castShadow ! undefined) {// 开启投射影响// eslint-disable-next-line no-param-reassignobj.castShadow true;// 开启被投射阴影// eslint-disable-next-line no-param-reassignobj.receiveShadow true;}});性能监视器stats 一个计算渲染分辨率FPS的工具在这里提一下。 引入 import Stats from three/examples/jsm/libs/stats.module;使用 // 性能监视器 let stats;document.getElementById(threeMain).appendChild(stats.domElement);function initStats() {stats new Stats();stats.showPanel(1); // 0: fps, 1: ms, 2: mb, 3: custom }function animation() {stats.update();renderer.render(scene, camera);composer.render();// mesh.rotateY(0.01);requestAnimationFrame(animation); }总结 这是我们实现目标的一个小小起点属于冰山一角前路漫漫还需要阅读很多知识文档和试错阶段如果你对后续感兴趣的话可以跟进一下呀谢谢 完整代码 import React, { useEffect } from react; import * as THREE from three; // eslint-disable-next-line import/extensions import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; // eslint-disable-next-line import/extensions import { OBJLoader } from three/examples/jsm/loaders/OBJLoader.js; import { MTLLoader } from three/examples/jsm/loaders/MTLLoader; import Stats from three/examples/jsm/libs/stats.module; // eslint-disable-next-line import/extensions import { GUI } from three/examples/jsm/libs/lil-gui.module.min.js;import { OutlinePass } from three/examples/jsm/postprocessing/OutlinePass; import { EffectComposer } from three/examples/jsm/postprocessing/EffectComposer; import { ShaderPass } from three/examples/jsm/postprocessing/ShaderPass; import { RenderPass } from three/examples/jsm/postprocessing/RenderPass; import { FXAAShader } from three/examples/jsm/shaders/FXAAShader; import { OutputPass } from three/examples/jsm/postprocessing/OutputPass;export default function ThreeVisual() {// 场景let scene;// 相机let camera;// 控制器let controls;// 网络模型let mesh;// 渲染器let renderer;// 性能监视器let stats;// debuggerlet gui;// 当前点击模型let clickModel;// 当前点击需要使用的let composer;let effectFXAA;let outlinePass;// debugger属性const debugObject {light: {amlight: {color: 0xffffff,},directionalLight: {color: 0xffffff,position: {x: 0,y: 400,z: 1800,},},pointLight: {color: 0xff0000,position: {x: 0,y: 400,z: 1800,},},},model: {wall: {position: {x: 0,y: 210,z: 0,},scale: 0.12,opacity: {wallTopOpa: 0.4,wallSideOpa: 1,},},camera: {position: {x: 100,y: 100,z: 100,},scale: 1,},},};// 模型对象const modelsObj {tunnelWall: {mtl: /model/tunnelWall.mtl,obj: /model/tunnelWall.obj,mesh: null,},camera: {mtl: /model/camera/摄像头方.mtl,obj: /model/camera/摄像头方.obj,mesh: null,},};const sizes {width: window.innerWidth,height: window.innerHeight,};// 获取鼠标坐标 处理点击某个模型的事件const mouse new THREE.Vector2(); // 初始化一个2D坐标用于存储鼠标位置const raycaster new THREE.Raycaster(); // 初始化光线追踪useEffect(() {// eslint-disable-next-line no-use-before-definethreeStart();}, []);const initThree () {const width document.getElementById(threeMain).clientWidth;const height document.getElementById(threeMain).clientHeight;renderer new THREE.WebGLRenderer({antialias: true,logarithmicDepthBuffer: true,});renderer.shadowMap.enabled true;renderer.setSize(width, height);document.getElementById(threeMain).appendChild(renderer.domElement);// renderer.setClearColor(0xFFFFFF, 1.0);document.getElementById(threeMain).appendChild(stats.domElement);};const initCamera (width, height) {camera new THREE.PerspectiveCamera(45, width / height, 0.1, 10000);camera.position.x 0;camera.position.y 500;camera.position.z 1300;camera.up.x 0;camera.up.y 1;camera.up.z 0;camera.lookAt({x: 0,y: 0,z: 0,});// 创建相机视锥体辅助对象// const cameraPerspectiveHelper new THREE.CameraHelper(camera);// scene.add(cameraPerspectiveHelper);};const initScene () {scene new THREE.Scene();scene.background new THREE.Color(0xbfd1e5);};const initLight () {const lightFolder gui.addFolder(光);const {directionalLight: debuggerDirectionalLight,pointLight: debuggerPointLight,} debugObject.light;// 环境光// const amlight new THREE.AmbientLight(debugObject.light.amlight.color);// amlight.position.set(1000, 1000, 1000);// scene.add(amlight);// // 环境光debugger// const amlightFolderlightFolder.addFolder(环境光)// amlightFolder.addColor(debugObject.light.amlight, color).onChange(function(value){// amlight.color.set(value);// });// 平行光// 创建平行光颜色为白色强度为 10const directionalLight new THREE.DirectionalLight(debuggerDirectionalLight.color, 1);// 设置平行光的方向directionalLight.position.set(0, 400, 1000);directionalLight.castShadow true;const directonalLightHelper new THREE.DirectionalLightHelper(directionalLight, 20);// scene.add(directonalLightHelper);scene.add(directionalLight);// 平行光debuggerconst directionalLightFolder lightFolder.addFolder(平行光);directionalLightFolder.addColor(debuggerDirectionalLight, color).onChange(function(value) {directionalLight.color.set(value);});// 平行光位置directionalLightFolder.add(debuggerDirectionalLight.position, x, -1000, 1000).onChange(function(value) {directionalLight.position.x value;directonalLightHelper.update();});directionalLightFolder.add(debuggerDirectionalLight.position, y, -1000, 1000).onChange(function(value) {directionalLight.position.y value;directonalLightHelper.update();});directionalLightFolder.add(debuggerDirectionalLight.position, z, -1000, 1000).onChange(function(value) {directionalLight.position.z value;directonalLightHelper.update();});// 点光源const pointLight new THREE.PointLight(debuggerPointLight.color, 1);pointLight.castShadow true;pointLight.position.set(100, 100, 300);const sphereSize 10;const pointLightHelper new THREE.PointLightHelper(pointLight, sphereSize);scene.add(pointLight);scene.add(pointLightHelper);const pointLightFolder lightFolder.addFolder(点光源);pointLightFolder.addColor(debuggerPointLight, color).onChange(function(value) {pointLight.color.set(value);});// 点光源位置pointLightFolder.add(debuggerPointLight.position, x, -1000, 1000).onChange(function(value) {pointLight.position.x value;pointLightHelper.update();});pointLightFolder.add(debuggerPointLight.position, y, -1000, 1000).onChange(function(value) {pointLight.position.y value;pointLightHelper.update();});pointLightFolder.add(debuggerPointLight.position, z, -1000, 1000).onChange(function(value) {pointLight.position.z value;pointLightHelper.update();});};const initObject () {const geometry new THREE.BoxGeometry(3000, 6, 2400);const loader new THREE.TextureLoader();const texture loader.load(/model/route.png, function(t) {// eslint-disable-next-line no-param-reassign,no-multi-assignt.wrapS t.wrapT THREE.RepeatWrapping;t.repeat.set(1, 1);});const material new THREE.MeshBasicMaterial({ color: 0xcccccc });geometry.position new THREE.Vector3(0, 0, 0);mesh new THREE.Mesh(geometry, [material, material, material, material, material, material]);mesh.receiveShadow true; // cast投射方块投射阴影scene.add(mesh);// 平面const geometryRoute new THREE.PlaneGeometry(1024, 2400);const materialRoute new THREE.MeshStandardMaterial({map: texture, // 使用纹理贴图side: THREE.BackSide, // 两面都渲染});const plane new THREE.Mesh(geometryRoute, materialRoute);plane.receiveShadow true;plane.position.set(0, 8, 0);plane.rotateX(Math.PI / 2);scene.add(plane);};const initControl () {// 将renderer关联到container这个过程类似于获取canvas元素const pcanvas document.getElementById(threeMain);controls new OrbitControls(camera, pcanvas);// 如果使用animate方法时将此函数删除// controls.addEventListener( change, render );// 使动画循环使用时阻尼或自转 意思是否有惯性controls.enableDamping true;// 动态阻尼系数 就是鼠标拖拽旋转灵敏度// controls.dampingFactor 0.25;// 是否可以缩放controls.enableZoom true;// 是否自动旋转// controls.autoRotate true;controls.autoRotateSpeed 0.5;// 设置相机距离原点的最近距离// controls.minDistance 10;// 设置相机距离原点的最远距离controls.maxDistance 10000;// 是否开启右键拖拽controls.enablePan true;};const onmodelclick event {console.log(event);// 获取鼠标点击位置mouse.x (event.clientX / sizes.width) * 2 - 1;mouse.y -(event.clientY / sizes.height) * 2 1;console.log(mouse);raycaster.setFromCamera(mouse, camera);const intersects raycaster.intersectObjects(scene.children); // 获取点击到的模型的数组从近到远排列// const worldPosition new THREE.Vector3(); // 初始化一个3D坐标用来记录模型的世界坐标if (intersects.length 0) {clickModel intersects[0].object;outlinePass.selectedObjects [];outlinePass.selectedObjects [clickModel];// intersects[0].object.getWorldPosition(worldPosition); // 将点中的3D模型坐标记录到worldPosition中// const texture new THREE.TextureLoader().load(/model/route.png);// const spriteMaterial new THREE.SpriteMaterial({// map: texture,// 设置精灵纹理贴图// });// const sprite new THREE.Sprite(spriteMaterial); // 精灵模型不管从哪个角度看都可以一直面对你// scene.add(sprite);// sprite.scale.set(40,40,40);// sprite.position.set(worldPosition.x, worldPosition.y 8, worldPosition.z); // 根据刚才获取的世界坐标设置精灵模型位置高度加了3是为了使精灵模型显示在点击模型的上方}};const initEvent () {window.addEventListener(resize, () {// Update sizessizes.width window.innerWidth;sizes.height window.innerHeight;// Update cameracamera.aspect sizes.width / sizes.height;camera.updateProjectionMatrix();// Update rendererrenderer.setSize(sizes.width, sizes.height);composer.setSize(sizes.width, sizes.height);renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));effectFXAA.uniforms.resolution.value.set(1 / sizes.width, 1 / sizes.height);});const pcanvas document.getElementById(threeMain);// 监听点击事件pcanvas.addEventListener(click, e onmodelclick(e)); // 监听点击};const loadModel () {const mtlLoader new MTLLoader();const loader new OBJLoader(); // 在init函数中创建loader变量用于导入模型mtlLoader.load(modelsObj.tunnelWall.mtl, material {material.preload();// 设置材质的透明度// mtl文件中的材质设置到obj加载器loader.setMaterials(material);loader.load(modelsObj.tunnelWall.obj, object {object.traverse(obj {if (obj.castShadow ! undefined) {// 开启投射影响// eslint-disable-next-line no-param-reassignobj.castShadow true;// 开启被投射阴影// eslint-disable-next-line no-param-reassignobj.receiveShadow true;}});// 设置模型大小object.children[0].geometry.computeBoundingBox();object.children[0].geometry.center();// debugger模型属性const { scale, position, opacity } debugObject.model.wall;// 模型本有属性const {scale: changeScale,position: changePositon,material: changeMaterial,} object.children[0];changeScale.set(scale, scale, scale);changePositon.set(position.x, position.y, position.z);changeMaterial[0].transparent true;changeMaterial[0].opacity opacity.wallTopOpa;changeMaterial[1].transparent true;changeMaterial[1].opacity opacity.wallSideOpa;modelsObj.tunnelWall.mesh object;scene.add(object);// 模型debuggerconst modelFolder gui.addFolder(模型);const wallFolder modelFolder.addFolder(墙);wallFolder.add(position, x, -100, 300).step(0.5).onChange(function(value) {changePositon.x value;});wallFolder.add(position, y, -100, 300).step(0.5).onChange(function(value) {changePositon.y value;});wallFolder.add(position, z, -100, 300).step(0.5).onChange(function(value) {changePositon.z value;});wallFolder.add(debugObject.model.wall, scale, 0.01, 0.3).step(0.001).onChange(function(value) {changeScale.set(value, value, value);});wallFolder.add(opacity, wallTopOpa, 0, 1).step(0.01).onChange(function(value) {changeMaterial[0].opacity value;});wallFolder.add(opacity, wallSideOpa, 0, 1).step(0.01).onChange(function(value) {changeMaterial[1].opacity value;});});});};// 克隆摄像头模型const cloneCameraModel (cameraSize, lrInterval, baInterval) {const group new THREE.Group();for (let i 0; i cameraSize; i 1) {modelsObj[camera${i}] modelsObj.camera.mesh.clone();modelsObj[camera${i}].position.set(lrInterval, 180, baInterval * (i % 2 0 ? -i : i));modelsObj[camera${i}].scale.set(1, 1, 1);group.add(modelsObj[camera${i}])}scene.add(group);};// 加载摄像头模型const loadCameraModel () {const mtlLoader new MTLLoader();const loader new OBJLoader(); // 在init函数中创建loader变量用于导入模型mtlLoader.load(modelsObj.camera.mtl, material {material.preload();// 设置材质的透明度// mtl文件中的材质设置到obj加载器loader.setMaterials(material);loader.load(modelsObj.camera.obj, object {object.traverse(obj {if (obj.castShadow ! undefined) {// 开启投射影响// eslint-disable-next-line no-param-reassignobj.castShadow true;// 开启被投射阴影// eslint-disable-next-line no-param-reassignobj.receiveShadow true;}});console.log(object);// 设置模型大小object.children[0].geometry.computeBoundingBox();object.children[0].geometry.center();// debugger模型属性object.children[0].scale.set(1, 1, 1);object.children[0].position.set(100, 100, 100);modelsObj.camera.mesh object;cloneCameraModel(4, 60, 180);cloneCameraModel(4, -200, 180);});});};// 效果合成器shader渲染使用const initEffectComposer () {// 处理模型闪烁问题【优化展示网格闪烁】// const parameters { format: THREE.RGBAFormat };// const size renderer.getDrawingBufferSize(new THREE.Vector2());// const renderTarget new THREE.WebGLMultipleRenderTargets(size.width, size.height, parameters);composer new EffectComposer(renderer);const renderPass new RenderPass(scene, camera);composer.addPass(renderPass);outlinePass new OutlinePass(new THREE.Vector2(sizes.width, sizes.height), scene, camera);outlinePass.visibleEdgeColor.set(255, 255, 0);outlinePass.edgeStrength 1.0; // 边框的亮度outlinePass.edgeGlow 1; // 光晕[0,1]outlinePass.usePatternTexture false; // 是否使用父级的材质outlinePass.edgeThickness 1.0; // 边框宽度outlinePass.downSampleRatio 1; // 边框弯曲度composer.addPass(outlinePass);const outputPass new OutputPass();composer.addPass(outputPass);effectFXAA new ShaderPass(FXAAShader);effectFXAA.uniforms.resolution.value.set(1 / sizes.width, 1 / sizes.height);composer.addPass(effectFXAA);};function animation() {stats.update();renderer.render(scene, camera);composer.render();// mesh.rotateY(0.01);requestAnimationFrame(animation);}function initHelper() {// const axesHelper new THREE.AxesHelper(3000);// scene.add(axesHelper);}function initStats() {stats new Stats();stats.showPanel(1); // 0: fps, 1: ms, 2: mb, 3: custom}function initDebugger() {gui new GUI();}function threeStart() {initEvent();initStats();initDebugger();initThree();initScene();initCamera(sizes.width, sizes.height);initHelper();initLight();initControl();initObject();loadModel();loadCameraModel();initEffectComposer();animation();}return div idthreeMain style{{ width: 100vw, height: 100vh }} /; }
http://www.hkea.cn/news/14563624/

相关文章:

  • 国外网站开发公司wordpress不能发表
  • 做网站需求文档北京手机网站设计费用
  • 甘肃网站建设专业品牌沧县网站建设公司
  • 红酒网站建设方案在线制作图片网站
  • 什么网站做招聘效果好网络服务合同需要缴纳印花税吗
  • 塑胶原料东莞网站建设标签云小工具 wordpress nofollow
  • 宁阳网站定制海口网站建设设计
  • 一流的常州做网站南京做南京华美整容网站
  • 广州网站建设比较wordpress中文页面
  • 有自己域名主机怎么做网站wordpress 定期删除
  • 专门做产品排名的网站东莞营销型高端网站建设
  • 广州网站seologo在线设计制作工具
  • 昆明贤邦网站建设北京展厅设计制作
  • 珠海正规网站制作系统编辑网站绑定
  • 江门网站建设运营团队设计公司属于什么企业类型
  • 资阳网页设计怎么做版式安卓优化清理大师
  • 广安发展建设集团门户网站设计制作活动主题
  • 做网站建设公司哪家好网页设计师介绍
  • wordpress的网站国内网响应式网站建设多少钱
  • 网站建设教程简笔画wordpress邮件发激活码
  • 做食品网站有哪些东西盐城网站建设服务
  • 沈阳网络建网站天长seo排名
  • 招聘桂林网站推广维护建设品牌展示型网站有哪些
  • 通过模版做网站广西建设职业技术学院教育网站
  • 不懂网站建设.怎么销售口碑好的常州做网站
  • 网站欢迎页面模板下载合肥企业建站系统
  • 陕西省西安市制作网站聊城做网站的公司案例
  • 网站推广填空题263邮箱个人登录入口
  • 网站建设方案多少钱多用户商城系统哪家好些
  • 建立网站的成本赣州搜赢网络科技有限公司