threejs自动巡游

threejs自动巡游自动巡游-有个需求是模拟保安巡检以及类似观光沿着轨道自动巡游,通过解析拆分。可以通过一系列的点连接成线,并将相机或保安模型沿着线进行运动,并调整其角度沿着切线方向保持~

自动巡游

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

有个需求是模拟保安巡检以及类似观光沿着轨道自动巡游,通过解析拆分。可以通过一系列的点连接成线,并将相机或
保安模型沿着线进行运动,并调整其角度沿着切线方向保持~

剖析

graph LR
鼠标拾取存储点位 --> 多点成线 --> 流光动画 --> 相机或模型沿线运动
需求分解:
 - 鼠标拾取三维坐标中的点(用于多点连接成线)
 - 多点成线(利用通道将点连接成通道)
 - 线段流光效果实现
 - 相机或模型沿线运动
解决方案:
 - 通过鼠标事件,拾取二维坐标转换为三维坐标
 - 存储点位三维坐标数组,生成对应的管道
 - 通过控制贴图的移动,实现流光效果
 - 实时改变更新相机或模型的位置以及朝向,实现沿线运动

鼠标拾取三维点位

- 通过鼠标拾取屏幕二维坐标
- 将二维坐标转换为三维坐标
- 将点位坐标记录下来
- 每次记录销毁之前的管道,生成新的管道
//双击事件
this.el.addEventListener('dblclick', function (e) {
  const mouse = new THREE.Vector2()
  mouse.x = (e.clientX / window.innerWidth) * 2 - 1
  mouse.y = -(e.clientY / window.innerHeight) * 2 + 1
  // 这里我们只检测模型的选中情况
  raycaster.setFromCamera(mouse, that.camera)
  const intersects = raycaster.intersectObjects(that.scene.children, true)
  if (intersects.length > 0) {
    var selected = intersects[0]//取第一个物体
    this.pointList.push(new THREE.Vector3(selected.point.x, 5, selected.point.z))//记录点位
    this.makeLine()//划线
  }
})
类的调用,生成一个巡游类,传入对应的场景、相机层级、相机、animate函数,通过不断销毁生成新的管道来
创建流光线
makeLine = function () {
  if (!this.zhdParade){//判断类是否存在
    this.zhdParade = new zhdParade({
      scene:this.scene, //场景
      layers:this.currentlayers, //层级
      camera:this.camera, //相机或者模型
      renderFunction:this.renderFunction //animate
    })
  }else{
    this.zhdParade.removeLine() //每次创建线要先销毁线
  }
  this.zhdParade.makeLine(this.pointList) //划线
}

自动巡游类的封装

由于上次的文章,一个老哥说代码太乱了,这回我贴上封装后的代码,虽然没有用上ts,但是这回应该不是很乱~~
有什么看不懂的地方可以留言,此次的代码量相对于之前较少也简单些~
以下是通用类的封装,基础类的继承就不放出来了
export class zhdParade extends zhdObject { //基础类
  constructor(options) {
    super()
    this.type = 'zhdParade'
    this.line = null
    this.texture = null
    this.camera=options.camera
    this.layers = options.layers
    this.scene = options.scene
    this.renderFunction = options.renderFunction
    this.texture_animate()
  }
}

画线

下面采用CatmullRomCurve3通道方法
通过鼠标拾取点位数组生成管道和线,生成管道主要用于移动巡游,线便于查看管道的形态
makeLine(pointList) {
  if (pointList.length < 2){
    return
  }
  this.curve = new THREE.CatmullRomCurve3(pointList) //管道
  this.curve.arcLengthDivisions = 1000
  this.texture = new THREE.TextureLoader().load('static/images/line.png') //贴图管道流光效果
  this.texture.wrapS = this.texture.wrapT = THREE.RepeatWrapping //每个都重复
  this.texture.repeat.set(1, 1)
  
  let tubeGeometry = new THREE.TubeGeometry(curve, 80, 1)
  let material = new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.BackSide,
    transparent: true
  })
  this.line = new THREE.Mesh(tubeGeometry, material)
  this.line.layers.set(this.layers)
  this.scene.add(this.line)
}

流光动画

通过改变线贴图的位置,形成流光效果
texture_animate() {
  this.renderFunction.push(() => { //animate
    if (this.texture) this.texture.offset.x -= 0.01 //改变贴图位置形成流光动画
  })
}

移除管道

避免线叠加,占用内存,创建新的线前移除存在的线
removeLine() {
  if (this.line) {
    this.scene.remove(this.line)
    this.line = null
  }
}

自动巡游

控制速度因素:
 - 两个点位之间的距离
 - progress累加的数值大小
 - 四维矩阵变化调整相机角度
简单描述:通过进度0-1之间的值来获取线上某个点的坐标,通过坐标来调整相机位置以及角度以及lookAt的位置
autoParade() {
  let progress = 0
  this.renderFunction.push(() => {//animate函数
    let offsetAngle = Math.PI*2 //角度
    if (this.carDirection === 'GO') { //沿着线前进
      if (progress > 1.0) {
        this.carDirection = 'BACK' //沿着线返回
      } else {
        progress += 0.0019 //
      }
    } else {
      // offsetAngle = -Math.PI / 2
      if (progress < 0) {
        this.carDirection = 'GO'
      } else {
        progress -= 0.0019
      }
    }
    if (this.curve && this.camera) {
      let point = this.curve.getPoint(progress) // 获取这个进度下线上某个进度点的坐标
      //模型的偏移量
      //创建一个4维矩阵
      let mtx = new THREE.Matrix4()
      mtx.lookAt(this.camera.position.clone(), point, this.camera.up) //相机看向的位置点
      mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)))
      //计算出需要进行旋转的四元数值
      let toRot = new THREE.Quaternion().setFromRotationMatrix(mtx)
      //根据以上值调整角度
      this.camera.quaternion.slerp(toRot, 1)
      this.camera.position.set(point.x, point.y, point.z)
    }
  })
}

今天的文章threejs自动巡游分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16600.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注