three.js工厂点击动画、标签

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 }

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-17 09:22:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-17 09:22:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-17 09:22:02       82 阅读
  4. Python语言-面向对象

    2024-03-17 09:22:02       91 阅读

热门阅读

  1. 贝叶斯定理,先验信念,似然,后验概率

    2024-03-17 09:22:02       46 阅读
  2. Hadoop基础架构及其特点解析

    2024-03-17 09:22:02       37 阅读
  3. C#编程语言在软件开发中的深度应用与实践

    2024-03-17 09:22:02       44 阅读
  4. C语言初阶测试

    2024-03-17 09:22:02       47 阅读
  5. DNS服务

    DNS服务

    2024-03-17 09:22:02      45 阅读
  6. Json格式解析

    2024-03-17 09:22:02       49 阅读
  7. [小程序开发] 构造页面

    2024-03-17 09:22:02       47 阅读
  8. React/RN组件避免重复渲染的一些技巧

    2024-03-17 09:22:02       43 阅读
  9. typeScript

    2024-03-17 09:22:02       43 阅读