赞
踩
html文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> body { overflow: hidden; margin: 0px; } .bu { background: rgba(0, 0, 0, 0.3); width: 60px; height: 60px; line-height: 60px; text-align: center; color: #fff; display: inline-block; border-radius: 30px; } .bu:hover { cursor: pointer; } .pos { position: absolute; left: 50%; margin-left: -135px; bottom: 100px; } #close:hover { cursor: pointer; } </style> </head> <!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 --> <body> <!-- backface-visibility: hidden;标签对应的HTML元素背面显示 --> <div id="tag" style="display: none;"> <!-- position:relative;约束子元素绝对定位参照点 --> <div style="position:relative;width:400px;height:322px;color: #fff;"> <!-- 图片绝对定位100%填充父元素,作为标签的背景 --> <img src="./model/信息背景.png" alt="" style="width:100%;position: absolute;left: 0px;top: 0px;"> <!-- 名称、存储量、设备状态、等信息叠加到背景图上即可 --> <div style="position:absolute;left:48px;top:36px;font-size:16px;"> <div style="font-size:20px;font-weight: 400;"> <span id="name">设备A</span> </div> <div style="margin-top: 30px;"> <span style="font-weight: 400;margin-left: 80px;font-size: 40px;color: #00ffff;">276559 L</span> </div> <div style="margin-top: 20px;"> <span style="color: #ccc;font-weight: 300;">管理</span><span style="font-weight: 400;margin-left: 30px;">快乐的小青蛙</span> </div> <div style="margin-top: 10px;"> <span style="color: #ccc;font-weight: 300;">工号</span><span style="font-weight: 400;margin-left: 30px;">666</span> </div> </div> <div style="position:absolute;left:285px;top:35px;"> <span style="color: #ffff00;">异常</span> </div> <div style="position:absolute;left:350px;top:20px;"> <img id="close" src="./model/关闭.png" width="32" style="pointer-events: auto;"> </div> </div> </div> <div id="webgl"></div> <script type="importmap"> { "imports": { "three": "../../../three.js/build/three.module.js", "three/addons/": "../../../three.js/examples/jsm/", "@tweenjs/tween.js":"./tween.esm.js" } } </script> <!-- 配置type="importmap",.html文件也能和项目开发环境一样方式引入threejs --> <script type="module" src="./04.工厂设备点击放大动画、标签动画.js"> </script> </body> </html>
04.工厂设备点击放大动画、标签动画.js
import gui from './gui.js' import tag from "./tag.js" import * as THREE from 'three' import { OrbitControls } from "three/addons/controls/OrbitControls.js" // 引入stats性能监视器 import Stats from "three/addons/libs/stats.module.js" // tween.js安装 npm i @tweenjs/tween.js@^18 import TWEEN from "@tweenjs/tween.js" // 引入CSS2渲染器CSS2DRenderer import { CSS2DRenderer } from 'three/addons/renderers/CSS2DRenderer.js'; // 1.引入后处理扩展库 import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js" // 2.引入渲染器通道 import { RenderPass } from "three/addons/postprocessing/RenderPass.js" // 3.引入OutlinePass通道 import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js" // 伽马矫正后处理shader import { GammaCorrectionShader } from "three/addons/shaders/GammaCorrectionShader.js" // ShaderPass功能:使用后处理Shader创建后处理通道 import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js" import { model } from "./mesh-modelDemo04.js" const stats = new Stats() stats.setMode(1)//修改渲染模式,默认为0 document.getElementById("webgl").appendChild(stats.domElement); // 创建一个三维场景 const scene = new THREE.Scene(); scene.add(model) // 坐标格辅助对象. 坐标格实际上是2维线数组. // const gridHelper = new THREE.GridHelper(600, 50, 0x00ffffff); // scene.add(gridHelper); // gridHelper.position.y = -1; // 创建辅助观察三维坐标 const axesHelper = new THREE.AxesHelper(100) scene.add(axesHelper)//坐标轴对象添加到三维场景中 // axesHelper.position.set(113, 33, 0) // 创建点光源 // const pointLight = new THREE.PointLight(0xffffff, 1.0); // pointLight.decay = 0.0//不随距离的改变而衰减 // pointLight.position.set(400, 200, 300)//设置光源位置 // scene.add(pointLight)//点光源添加到场景中 // 光源辅助观察 // const pointLightHelper = new THREE.PointLightHelper(pointLight, 10) // scene.add(pointLightHelper) // 添加一个环境光源 const ambient = new THREE.AmbientLight(0xffffff, 0.9) scene.add(ambient) console.log('光照强度', ambient.intensity); // 添加一个平行光 const directionalLight = new THREE.DirectionalLight(0xffffff, 2) directionalLight.position.set(100, 60, 100); // directionalLight.target = mesh//默认坐标原点 scene.add(directionalLight) // 可视化平行光 const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 10, 0xff0000) scene.add(dirLightHelper) const ambientFolder = gui.addFolder('环境光') ambientFolder.close() // 环境光强度 ambientFolder.add(ambient, 'intensity', 0, 2).name('环境光.intensity') const dirFolder = gui.addFolder('平行光') // dirFolder.close() // 平行光强度 dirFolder.add(directionalLight, 'intensity', 0, 4) // const dirFolder2 = dirFolder.addFolder('位置') // dirFolder2.close() const width = window.innerWidth const height = window.innerHeight // 创建一个透视投影相机对象 const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000); // 设置相机位置 camera.position.set(292, 223, 185); // 相机视线观察目标点坐标 camera.lookAt(0, 0, 0)//坐标原点 // const R = 100 // new TWEEN.Tween({ angle: 0 }) // .to({ angle: Math.PI * 2 }, 16000) // .onUpdate(function (obj) { // camera.position.x = R * Math.cos(obj.angle); // camera.position.z = R * Math.sin(obj.angle); // camera.lookAt(0, 0, 0)//坐标原点 // }) // .start() // 渲染器 // 创建一个WebGL渲染器 const renderer = new THREE.WebGLRenderer({ antialias: true,//锯齿模糊 logarithmicDepthBuffer: true,//设置对数深度缓冲区,优化深度冲突问题 // preserveDrawingBuffer: true,//想要把cavas画布上内容下载到本地,需要设置为true }); renderer.setSize(width, height);//canvas画布宽高度 renderer.shadowMap.enabled = true;//设置渲染器,允许光源阴影渲染 renderer.shadowMap.type = THREE.VSMShadowMap;//阴影条纹问题解决 // renderer.setClearColor(0x00ffff) // 告诉thressjs你的屏幕的设备像素比 renderer.setPixelRatio(window.devicePixelRatio);//pixel设备像素比 console.log('查看当前屏幕设备像素比', window.devicePixelRatio); document.getElementById("webgl").appendChild(renderer.domElement); // 1.创建后处理对象EffectComposer,WebGL渲染器作为参数 const composer = new EffectComposer(renderer) // 2.创建一个渲染器通道,场景和相机作为参数 const renderPass = new RenderPass(scene, camera) composer.addPass(renderPass) //3. OutlinePass第一个参数V2的尺寸和cavas画布尺寸保持一致 const v2 = new THREE.Vector2(window.innerWidth, window.innerHeight); const outlinePass = new OutlinePass(v2, scene, camera) // outlinePass.selectedObjects = [model.children[0]] composer.addPass(outlinePass) // 模型描边颜色,默认是白色 outlinePass.visibleEdgeColor.set(0x00ffff) // 高亮发光厚度 outlinePass.edgeThickness = 4 // 高亮描边发光强度 outlinePass.edgeStrength = 6 // 模型闪烁频率控制 outlinePass.pulsePeriod = 2 // 创建伽马校正通道(设置EffectComposer) const gammaPass = new ShaderPass(GammaCorrectionShader) composer.addPass(gammaPass) // 创建一个css2d渲染器 const css2DRenderer = new CSS2DRenderer(); css2DRenderer.setSize(width, height); css2DRenderer.domElement.style.position = "absolute"; css2DRenderer.domElement.style.top = "0px"; document.body.appendChild(css2DRenderer.domElement); css2DRenderer.domElement.style.pointerEvents = "none"; renderer.domElement.style.zIndex = -1 css2DRenderer.domElement.style.zIndex = 1 function render() { TWEEN.update() composer.render(); css2DRenderer.render(scene, camera); stats.update() // TWEEN.update() // renderer.render(scene, camera);//周期性执行相机的渲染功能,更新canvas画布上的内容 requestAnimationFrame(render) } render() // 创建一个相机控件对象 const controls = new OrbitControls(camera, renderer.domElement); controls.update() controls.addEventListener('change', function () { renderer.render(scene, camera)//执行一个渲染操作,类比相机拍照咔 }) // onresize事件会在窗口被调整大小时发生 window.onresize = function () { const width = window.innerWidth const height = window.innerHeight css3DRenderer.setSize(width, height); camera.aspect = width / height;//全屏情况下:设置观察范围长宽比aspect为窗口宽高比 camera.updateProjectionMatrix();//相机属性发生变化,需要执行updateProjectionMatrix()方法更新 renderer.setSize(width, height);//重置渲染器输出画布canvas尺寸 renderer.render(scene, camera); } // 声明存储选中的模型 let chooseObj = null const span = document.getElementById('name') const cameraPos0 = new THREE.Vector3(292, 223, 185) const target0 = new THREE.Vector3(0, 0, 0); addEventListener('click', function (event) { const px = event.offsetX const py = event.offsetY // 屏幕坐标px、py转换为三维坐标x、y // width、height表示canvas画布的宽高 const x = (px / width) * 2 - 1 const y = -(py / height) * 2 + 1 console.log('x', x) console.log('y', y) // 创建一个射线投射器 const raycaster = new THREE.Raycaster() raycaster.setFromCamera(new THREE.Vector2(x, y), camera) const cunchu = model.getObjectByName('存储罐') console.log(cunchu); for (let i = 0; i < cunchu.children.length; i++) { const group = cunchu.children[i] group.traverse(function (obj) { if (obj.isMesh) { obj.ancestors = group } }) } const intersects = raycaster.intersectObjects(cunchu.children) console.log(intersects); if (intersects.length > 0) { span.innerHTML = intersects[0].object.ancestors.name const obj = intersects[0].object.ancestors const pos = new THREE.Vector3(); // 获取三维场景中某个对象世界坐标 obj.getWorldPosition(pos); // 向量x、y、z坐标分别在pos基础上增加30 const pos2 = pos.clone().addScalar(30); createCameraTween(pos2, pos) obj.add(tag) // 可视化模型 // const axesHelper = new THREE.AxesHelper(100); // obj.add(axesHelper); console.log(intersects[0].object.ancestors); outlinePass.selectedObjects = [intersects[0].object.ancestors]; chooseObj = intersects[0].object.ancestors // 获取模型对象对应的标注点 // const obj = model.getObjectByName(intersects[0].object.ancestors.name + '标注') // console.log(obj); // obj.add(tag) } else { if (chooseObj) {//把原来选中模型对应的标签和发光描边隐藏 outlinePass.selectedObjects = []//无发光描边 console.log(chooseObj); chooseObj.remove(tag)//从场景移除 // 相机从当前位置camera.position回到整体预览状态 createCameraTween(cameraPos0, target0) } } }) // 相机动画函数,从A点飞行到B点,A点表示相机当前所处状态 // pos: 三维向量Vector3,表示动画结束相机位置 // target: 三维向量Vector3,表示相机动画结束lookAt指向的目标观察点 function createCameraTween(endPos, endTarget) { new TWEEN.Tween({ // 不管相机此刻处于什么状态,直接读取当前的位置和目标观察点 x: camera.position.x, y: camera.position.y, z: camera.position.z, tx: controls.target.x, ty: controls.target.y, tz: controls.target.z, }) .to({ // 动画结束相机位置坐标 x: endPos.x, y: endPos.y, z: endPos.z, // 动画结束相机指向的目标观察点 tx: endTarget.x, ty: endTarget.y, tz: endTarget.z, }, 2000) .onUpdate(function (obj) { // 动态改变相机位置 camera.position.set(obj.x, obj.y, obj.z); // 动态计算相机视线 // camera.lookAt(obj.tx, obj.ty, obj.tz); controls.target.set(obj.tx, obj.ty, obj.tz); controls.update();//内部会执行.lookAt() }) .start(); } document.getElementById('close').addEventListener('click', function () { if (chooseObj) {//把原来选中模型对应的标签和发光描边隐藏 outlinePass.selectedObjects = []//无发光描边 console.log(chooseObj); chooseObj.remove(tag)//从场景移除 // 相机从当前位置camera.position回到整体预览状态 createCameraTween(cameraPos0, target0) } })
tag.js
// 引入CSS2渲染器CSS2DRenderer
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
const div = document.getElementById('tag')
div.style.top = '-161px'//指示线端点和标注点重合
// HTML元素转化为threejs的css2模型对象
const tag = new CSS2DObject(div)
export default tag
mesh-modelDemo04.js
import * as THREE from 'three' // 引入gltf加载器 import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' // 实例化一个加载器对象 const loader = new GLTFLoader() const model = new THREE.Group() loader.load('./model/工厂.glb', function (gltf) { console.log('gltg', gltf); model.add(gltf.scene) }) export { model }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。