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

慈云数据 1年前 (2024-03-20) 技术支持 54 0
html文件



  
  
  Document
  
    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;
    }
  



  
  
  
{ "imports": { "three": "../../../three.js/build/three.module.js", "three/addons/": "../../../three.js/examples/jsm/", "@tweenjs/tween.js":"./tween.esm.js" } }

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  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 }
微信扫一扫加客服

微信扫一扫加客服