three.js使用轨迹球控件TrackballControls控制相机(vue中使用three.js62)

1.demo效果

在这里插入图片描述

如上图,该demo通过轨迹球控件TrackballControls控制相机。实现通过按住鼠标左键拖动控制场景旋转、翻滚相机,通过鼠标滚轮控制场景放大缩小,通过按住鼠标右键拖动控制场景平移,通过右上角的"resetCamera"按钮重置相机位置

2.TrackballControls介绍

通过轨迹球控件TrackballControls 我们可以实现场景的旋转、缩放、平移等功能

2.1 TrackballControls操控说明

以下是动作和操控比对说明

动作操控
在场景中旋转、翻滚相机按住鼠标左键拖动
放大和缩小转动鼠标滚轮或按住鼠标中键拖动
在场景中平移按住鼠标右键拖动

2.2 TrackballControls属性介绍

我们创建TrackballControls实例后。它有一些属性来告诉控件如何工作,现在来认识一下它们

属性描述
enabled是否开启控制器,默认true,如果设置为false,对相机的操作将失效
rotateSpeed相机的旋转速度,默认 3.0
zoomSpeed相机的缩放速度,默认 1.2
panSpeed相机的平移速度,默认 0.3
noRotate是否关闭相机旋转,默认 false
noZoom是否关闭相机缩放,默认 false
noPan是否关闭相机移动,默认 false
staticMoving是否关闭拖拽惯性移动,默认 false
dynamicDampingFactor拖拽惯性移动阻力,默认 0.2
minDistance相机距离焦点的最近距离,默认 0
maxDistance相机距离焦点的最远距离,默认 Infinity(无限远)

2.3 TrackballControls方法介绍

2.3.1 update()函数

TrackballControls控件控制相机更新的方法,需要在循环动画函数中调用,通常在render函数中调用

render() {
  this.trackballControls.update() // 相机更新
  this.renderer.render(this.scene, this.camera)
  requestAnimationFrame(this.render)
}

2.3.2 reset()函数

重置相机的方法,该函数可以使相机回到初始位置

2.3.3 dispose()函数

销毁实例化的TrackballControls对象

2.3.4 change()回调函数

有了这个函数我们可以监听相机变化事件,如果控制器调整了相机的位置,可以被监听到,就可以在回调函数中做相应的处理,添加监听的方式如下:

this.trackballControls.addEventListener('change', function(event) {
  console.log(event)
  //这里可以做一些基于相机位置变化的事情
})

3.实现要点

3.1 vue中引入TrackballControls控制器

在项目工程中引入TrackballControls 控制器的方式如下:

import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'

3.2 创建TrackballControls实例

// 创建轨迹球控件
createTrackballControls() {
  this.clock = new THREE.Clock() //创建THREE.Clock对象,用于计算上次调用经过的时间
  this.trackballControls = new TrackballControls(
    this.camera,
    this.renderer.domElement
  )

  this.trackballControls.rotateSpeed = 1.0 //相机的旋转速度
  this.trackballControls.zoomSpeed = 1.0 //相机的缩放速度
  this.trackballControls.panSpeed = 1.0 //相机的平移速度
  this.trackballControls.staticMoving = true //关闭拖拽惯性移动
  //添加相机移动监听事件
  this.trackballControls.addEventListener('change', function(event) {
    console.log(event)
    //这里可以做一些基于相机位置变化的事情
  })
}

3.3 相机重置处理

resetCamera() {
  this.trackballControls.reset()
}

3.4 render中处理相机更新

render() {
  const delta = this.clock.getDelta() // 获取自上次调用的时间差
  this.trackballControls.update(delta) // 相机更新
  this.renderer.render(this.scene, this.camera)
  requestAnimationFrame(this.render)
}

3.5 加载OBJ和MTL组合模型

首先要引入OBJ和MTL加载工具

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js'
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js'

加载模型实现

// 加载OBJ、MTL模型
loadObjMtl() {
  const mtlLoader = new MTLLoader()
  const objLoader = new OBJLoader()
  const THIS = this
  mtlLoader.load(`${THIS.publicPath}models/city.mtl`, material => {
    material.preload()
    objLoader.setMaterials(material) //mtl文件中的材质设置到obj加载器
    return objLoader.load(
      `${THIS.publicPath}models/city.obj`,
      loadedMesh => {
        THIS.mesh = loadedMesh
        loadedMesh.scale.set(0.2, 0.2, 0.2)
        THIS.setRandomColors(loadedMesh, THIS)
        THIS.scene.add(THIS.mesh)
      }
    )
  })
},
//给材质设置红黄绿随机色,并设置透明度
setRandomColors(object, THIS) {
  const children = object.children

  if (children && children.length > 0) {
    children.forEach(function(e) {
      THIS.setRandomColors(e, THIS)
    })
  } else {
    if (object instanceof THREE.Mesh) {
      const colorIndex = Math.floor(Math.random() * 3) //0~2的随机数
      const colorArray = [
        new THREE.Color(0xff0000),
        new THREE.Color(0x00ff00),
        new THREE.Color(0x0000ff)
      ]
      object.material.color = colorArray[colorIndex]
      object.material.transparent = true
      object.material.opacity = 0.3
      if (
        object.material.name &&
        object.material.name.indexOf('building') == 0
      ) {
        object.material.emissive = colorArray[colorIndex]
        object.material.transparent = true
        object.material.opacity = 0.3
      }

      //重新计算面法向量和顶点法向量,修复模型导入为重黑色
      object.geometry.computeFaceNormals()
      object.geometry.computeVertexNormals()
    }
  }
}

4.demo代码

<template>
  <div>
    <div id="container"></div>
    <div class="controls-box">
      <section>
        <el-row>
          <el-button type="primary" class="controls-button" size="mini" @click="resetCamera">resetCamera</el-button>
        </el-row>
      </section>
    </div>
  </div>
</template>
<script>
import * as THREE from 'three'
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js'
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js'

export default {
  data() {
    return {
      publicPath: process.env.BASE_URL,
      mesh: null,
      camera: null,
      scene: null,
      renderer: null,
      trackballControls: null,
      clock: null
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    // 初始化
    init() {
      this.createScene() // 创建场景
      this.loadObjMtl() // 加载OBJ、MTL模型
      this.createLight() // 创建光源
      this.createCamera() // 创建相机
      this.createRender() // 创建渲染器
      this.createTrackballControls() // 创建轨迹球控件
      this.render() // 渲染
    },
    // 创建场景
    createScene() {
      this.scene = new THREE.Scene()
    },
    // 加载OBJ、MTL模型
    loadObjMtl() {
      const mtlLoader = new MTLLoader()
      const objLoader = new OBJLoader()
      const THIS = this
      mtlLoader.load(`${THIS.publicPath}models/city.mtl`, material => {
        material.preload()
        objLoader.setMaterials(material) //mtl文件中的材质设置到obj加载器
        return objLoader.load(
          `${THIS.publicPath}models/city.obj`,
          loadedMesh => {
            THIS.mesh = loadedMesh
            loadedMesh.scale.set(0.2, 0.2, 0.2)
            THIS.setRandomColors(loadedMesh, THIS)
            THIS.scene.add(THIS.mesh)
          }
        )
      })
    },
    //给材质设置红黄绿随机色,并设置透明度
    setRandomColors(object, THIS) {
      const children = object.children

      if (children && children.length > 0) {
        children.forEach(function(e) {
          THIS.setRandomColors(e, THIS)
        })
      } else {
        if (object instanceof THREE.Mesh) {
          const colorIndex = Math.floor(Math.random() * 3) //0~2的随机数
          const colorArray = [
            new THREE.Color(0xff0000),
            new THREE.Color(0x00ff00),
            new THREE.Color(0x0000ff)
          ]
          object.material.color = colorArray[colorIndex]
          object.material.transparent = true
          object.material.opacity = 0.3
          if (
            object.material.name &&
            object.material.name.indexOf('building') == 0
          ) {
            object.material.emissive = colorArray[colorIndex]
            object.material.transparent = true
            object.material.opacity = 0.3
          }

          //重新计算面法向量和顶点法向量,修复模型导入为重黑色
          object.geometry.computeFaceNormals()
          object.geometry.computeVertexNormals()
        }
      }
    },
    // 创建光源
    createLight() {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.1) // 创建环境光
      this.scene.add(ambientLight) // 将环境光添加到场景

      const spotLight = new THREE.SpotLight(0xffffff) // 创建聚光灯
      spotLight.position.set(200, 200, 200)
      spotLight.castShadow = true
      this.scene.add(spotLight)
    },
    // 创建相机
    createCamera() {
      const element = document.getElementById('container')
      const width = element.clientWidth // 窗口宽度
      const height = element.clientHeight // 窗口高度
      const k = width / height // 窗口宽高比
      this.camera = new THREE.PerspectiveCamera(35, k, 0.1, 1000)
      this.camera.position.set(-80, 60, 40) // 设置相机位置

      this.camera.lookAt(new THREE.Vector3(10, 0, 0)) // 设置相机方向
      this.scene.add(this.camera)
    },
    // 创建渲染器
    createRender() {
      const element = document.getElementById('container')
      this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
      this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
      this.renderer.shadowMap.enabled = true // 显示阴影
      this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
      this.renderer.setClearColor(0x3f3f3f, 1) // 设置背景颜色
      element.appendChild(this.renderer.domElement)
    },

    render() {
      const delta = this.clock.getDelta() // 获取自上次调用的时间差
      this.trackballControls.update(delta) // 相机更新
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    },
    //相机恢复
    resetCamera() {
      this.trackballControls.reset()
    },
    // 创建轨迹球控件
    createTrackballControls() {
      this.clock = new THREE.Clock() //创建THREE.Clock对象,用于计算上次调用经过的时间
      this.trackballControls = new TrackballControls(
        this.camera,
        this.renderer.domElement
      )

      this.trackballControls.rotateSpeed = 1.0 //相机的旋转速度
      this.trackballControls.zoomSpeed = 1.0 //相机的缩放速度
      this.trackballControls.panSpeed = 1.0 //相机的平移速度
      this.trackballControls.staticMoving = true //关闭拖拽惯性移动
      //添加相机移动监听事件
      this.trackballControls.addEventListener('change', function(event) {
        console.log(event)
        //这里可以做一些基于相机位置变化的事情
      })
    }
  }
}
</script>
<style>
#container {
  position: absolute;
  width: 100%;
  height: 100%;
}
.controls-box {
  position: absolute;
  right: 5px;
  top: 5px;
  width: 300px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #c3c3c3;
}
</style>

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对整threeJS体系进行全面剖析。整理出全面的教学大纲,涵盖内容面非常广。此教学版本为threeJS107版本。关于版本不建议大家使用低于90的版本学习。以下是课程目录1-ThreeJS概览(基本图形简介,什么是点线面如何绘制点线面,什么是材质,什么是几何体,什么是相机,什么是渲染器,什么是场景)2-相机和渲染器(详解相机类型,渲染器如何使用,针对不同场景怎么用,怎么调效果,怎么渲染,怎么输出画布,如何解决透明问题等等)3-创建平面几何(常见的几何体如何使用,如何使用简单的几何体绘制出自定义自己想要的几何体,关于几何体的性能剖析,如何解决性能,几何体的渲染原理)4-高级图形算法常见库(求直线的斜率  计算线段与圆的交点 计算线段的长度 判断折线是否在多边形内 等等)5-sprite精灵(怎么让一个图标永远朝向屏幕,精灵的属性,精灵材质原理等,广告提示框必用)6-骨骼游戏动画(什么是模型动画,常见游戏案例,如何让人头进行各种攻击动作)7-3d模型加载(常见模型格式,如何渲染不同格式,不同格式的特点,什么格式性能优越,模型渲染异常,贴图不显示等问题详解)8-高阶动态纹理(你所不知道的纹理用法,我说你不知道,你肯定不知道)9-漫游轨迹以及其动画路径(怎么绘制贝塞尔曲线,如何使用曲线上的路径,跟随路径移动的原理,相机如何运动,物体如何运动)10-着色器(什么是着色器。初识着色器基础,着色器材质怎么用,怎么使用着色器库)11-常见渲染以及透明度问题12-对象拾取以及拖拽(3d世界里面如何拖拽物体,拖拽的原理,mousemove mouseon等的事件效果)13-世界坐标以及组的问题(什么是相对坐标,什么是世界坐标,什么是当前坐标,怎么转化父子坐标系,组的优化,为什么用组,组的优势)14-指定对象旋转心(什么是物体的几何体心,如何改变心,如何绕轴转动)15-层级对象渲染(多个场景一键切换,切换的优势,针对大项目的用法)16-拓展了解系列(不定期不断更新案例,各种酷炫效果bloom,halo等,以及各种3d图表,粒子案例等,不断构建你的3d实践能力)
### 回答1: 你可以在Vue3使用Three.js,首先需要安装Three.js库,然后在Vue组件引入Three.js库,可以使用import语句引入。接着,你可以在Vue组件使用Three.js的API来创建3D场景、模型等。需要注意的是,在Vue3使用Three.js时,需要使用Vue的生命周期函数来管理Three.js的渲染和更新。具体实现方法可以参考Three.js官方文档和Vue3官方文档。 ### 回答2: 在Vue3使用Three.js可以通过以下步骤实现: 1. 在你的Vue项目安装Three.js库。可以使用npm或者yarn来安装,命令如下: ``` npm install three ``` 或 ``` yarn add three ``` 2. 在Vue组件引入Three.js库。在需要使用Three.js的组件文件,添加以下代码: ```js import * as THREE from 'three'; ``` 这样,你就可以在该组件使用Three.js提供的所有功能和类。 3. 创建Three.js场景和渲染器。在Vue组件的`mounted`钩子函数,创建一个空的Three.js场景,并将其渲染到HTML页面上的某个容器,代码如下: ```js const scene = new THREE.Scene(); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.getElementById('container').appendChild(renderer.domElement); ``` 4. 添加和渲染Three.js的物体。在场景创建并添加需要渲染的物体,如立方体等,然后通过调用渲染器的`render`函数将场景渲染到页面上,代码如下: ```js const geometry = new THREE.BoxGeometry(); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); renderer.render(scene, camera); // 其camera为相机对象,需要提前创建并设置 ``` 5. 在Vue组件使用动画循环更新场景。你可以使用Vue的`watch`侦听器或者使用Vue提供的动画插件,来持续更新Three.js场景的状态,并在每一帧重新渲染场景,以实现动态效果。 以上就是在Vue3使用Three.js的基本步骤。通过这些步骤,你可以在Vue项目使用Three.js创建出交互式和动态的3D图形。 ### 回答3: 在Vue3使用Three.js的步骤如下: 1. 安装Three.js:可以通过npm或者yarn命令行安装Three.js库。在项目根目录打开终端,执行以下命令: ``` npm install three ``` 或者 ``` yarn add three ``` 2. 创建Vue组件:在Vue项目创建一个新的Vue组件,用来承载Three.js场景和渲染器。可以在方法或者生命周期函数编写Three.js逻辑。 3. 引入Three.js:在Vue组件使用import语句引入Three.js库: ```javascript import * as THREE from 'three' ``` 4. 创建场景、渲染器和相机:在Vue组件的mounted生命周期函数创建Three.js所需的场景、渲染器和相机: ```javascript mounted () { const scene = new THREE.Scene() const renderer = new THREE.WebGLRenderer() const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) renderer.setSize(window.innerWidth, window.innerHeight) this.$refs.container.appendChild(renderer.domElement) } ``` 5. 添加物体和光源:可以在Vue组件的mounted生命周期函数添加物体和光源到场景: ```javascript const geometry = new THREE.BoxGeometry() const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) const cube = new THREE.Mesh(geometry, material) scene.add(cube) const light = new THREE.PointLight(0xffffff) light.position.set(0, 0, 10) scene.add(light) ``` 6. 渲染场景:在Vue组件的mounted生命周期函数使用requestAnimationFrame函数循环渲染场景: ```javascript function animate () { requestAnimationFrame(animate) renderer.render(scene, camera) } animate() ``` 7. 更新和交互:可以在Vue组件监听鼠标和键盘事件,并根据需要更新Three.js场景。 这些是在Vue3使用Three.js的基本步骤。根据具体需求,还可以使用其他Three.js功能,如纹理贴图、动画等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值