第二课threejs模型场景控制器

## 

> 背景: 创建出threejs 3D场景后如何使用鼠标操作场景内模型元素?,如拖动,放大缩小,平移,点击触发交互等。。。

#### 安装threejs控制器组件

```js

npm install three-orbitcontrols -D

```

#### 第一步

> 创建盛放场景盒子div

```js

```

#### 第二步

> 引入vue, threejs , three-orbitcontrols

```js

import Vue from 'vue';

import * as THREE from 'three';

import * as OrbitControls from 'three-orbitcontrols'

```

#### 第三步

> 创建基础的data数据

```js

data (): DataType {

  return {

    id: null,

    domW: 0,

    domH: 0,

    scene: null,

    camera: null,

    renderer: null,

    mesh: null,

    controls: null

  }

},

```

#### 第四步

> 初始运行创建场景,获取场景宽度高度

```js

mounted () {

  // 获取盛放场景div标签

  this.id = document.getElementById('threeone')

  // 获取盛放标签宽高

  this.domW = this.id.offsetWidth

  this.domH = this.id.offsetHeight

  // 运行创建场景函数

  this.init()

},

```

#### 第五步

> 创建场景函数讲解

  -- 1. 知识点讲解 ---

  a. `new THREE.PerspectiveCamera(45, this.domW / this.domH, 0.01, 20000)`

    // 设置相机 45 摄像机视锥体垂直视野角度, 

    // this.domW / this.domH 摄像机视锥体长宽比

    // 0.01 摄像机视锥体近端面(摄像机拍摄最近距离)

    // 20000 摄像机拍摄最远距离,超出距离模型场景不显示


  b. `new THREE.WebGLRenderer({ antialias: true, alpha: true })`

    ```js

    WebGLRenderer( parameters : Object )

    // canvas - 一个供渲染器绘制其输出的canvas 它和下面的domElement属性对应。 如果没有传这个参数,会创建一个新canvas

    // context - 可用于将渲染器附加到已有的渲染环境(RenderingContext)中。默认值是null

    // precision - 着色器精度. 可以是 "highp", "mediump" 或者 "lowp". 如果设备支持,默认为"highp" 

    // alpha - canvas是否包含alpha (透明度)。默认为 false

    // antialias - 是否执行抗锯齿。默认为false. 避免模型渲染出现锯齿现象

    // stencil - 绘图缓存是否有一个至少8位的模板缓存(stencil buffer)。默认为true

    // preserveDrawingBuffer -是否保留缓缓存直到手动清除或被覆盖。 默认false.

    // depth - 绘图缓存是否有一个至少6位的深度缓存(depth buffer )。 默认是true.

    // logarithmicDepthBuffer - 是否使用对数深度缓存。如果要在单个场景中处理巨大的比例差异,就有必要使用。

    ```

> init 函数讲解

  ```js

    init () {

      // 实例化场景函数

      this.scene = new THREE.Scene()

      // 设置相机

      this.camera = new THREE.PerspectiveCamera(45, this.domW / this.domH, 0.01, 20000)

      // 摄像机z轴位置

      this.camera.position.z = 800

      // this.camera.position.y = 100

      // 实例化渲染器

      this.renderer = new THREE.WebGLRenderer({

        antialias: true,

        alpha: true

      })

      // 设置渲染器宽高

      this.renderer.setSize(this.domW, this.domH)

      //将渲染器append到div容器中

      this.id.appendChild(this.renderer.domElement)

      // 添加灯光

      this.addLight()

      // 添加辅助线

      this.axisHelper()

      // 创建正方体

      this.initBox()

      // 刷帧渲染动画

      this.animate()

      // 响应屏幕改变大小函数

      this.onWindowResize()

      // 场景控制器函数

      this.controlsFn()

    },

  ```

  #### 第五步

  > 添加灯光

  ```js

  addLight () {

      // 设置环境光

      const ambientLight = new THREE.AmbientLight('#ffffff')

      this.scene.add(ambientLight)

      // 设置平行光

      const light = new THREE.DirectionalLight('#ffffff')

      this.scene.add(light)

      // 设置点光源

      const pointLight = new THREE.PointLight('#ffffff', 0.1, 1000)

      pointLight.position.set(300, 300, 300)

      this.scene.add(pointLight)

    },

  ```

  #### 第六步

  > 添加空间辅助线

  ```js

  axisHelper () {

      // 空间辅助线函数

      const axes:THREE.AxesHelper = new THREE.AxesHelper(800)

      this.scene.add(axes)

  },

  ```

  #### 第七步

  > 创建正方体和网格圆球

    -- 1. 创建球体知识点 --

    a. `new THREE.SphereGeometry()`

    ```js

      new THREE.SphereGeometry(radius : Float, widthSegments : Integer, heightSegments : Integer, phiStart : Float, phiLength : Float, thetaStart : Float, thetaLength : Float)


      // radius — 球体半径,默认为1。

      // widthSegments — 水平分段数(沿着经线分段),最小值为3,默认值为8。

      // heightSegments — 垂直分段数(沿着纬线分段),最小值为2,默认值为6。

      // phiStart — 指定水平(经线)起始角度,默认值为0。

      // phiLength — 指定水平(经线)扫描角度的大小,默认值为 Math.PI * 2。

      // thetaStart — 指定垂直(纬线)起始角度,默认值为0。

      // thetaLength — 指定垂直(纬线)扫描角度大小,默认值为 Math.PI。

      // 该几何体是通过扫描并计算围绕着Y轴(水平扫描)和X轴(垂直扫描)的顶点来创建的。 因此,不完整的球体(类似球形切片)可以通过为phiStart,phiLength,thetaStart和thetaLength设置不同的值来创建, 以定义我们开始(或结束)计算这些顶点的起点(或终点)。


    ```

> initBox 函数讲解

```js

initBox () {

  // 添加正方体

  const geometry = new THREE.BoxGeometry(200, 200, 200)

  // 添加正方体材质

  const material = new THREE.MeshBasicMaterial({ color: '#ffffff', map: new THREE.TextureLoader().load('https://www.douchuanwei.com/api/files/img/1.jpeg') })

  // 合成正方体mesh网格

  this.mesh = new THREE.Mesh(geometry, material)

  this.scene.add(this.mesh)

  // 创建球体

  const geometry2 = new THREE.SphereGeometry(60, 20, 60)

  // 创建球体材质

  const material2 = new THREE.MeshLambertMaterial({

    color: 'red',

    wireframe: true

    // emissive:0xad1919,

    // vertexColors: THREE.NoColors

    // specular:0x4488ee,

    // shininess: 12

  })

  // 将球体和材质添加到mesh网格

  const mesh2 = new THREE.Mesh(geometry2, material2)

  // 球体从中心点向x轴平移250

  mesh2.translateX(250)

  this.scene.add(mesh2)

  // 创建第二个球体

  const geometry3 = new THREE.SphereGeometry(60, 20, 60)

  const material3 = new THREE.MeshLambertMaterial({

    color: 'red', // 红色球体

    wireframe: true // 将球体变成网格

    // emissive:0xad1919,

    // vertexColors: THREE.NoColors

    // specular:0x4488ee,

    // shininess: 12

  })

  const mesh3 = new THREE.Mesh(geometry3, material3)

  mesh3.translateX(-250)

  this.scene.add(mesh3)

},

```

#### 第八步

> 帧渲染动画,让场景动起来

```js

animate () {

  window.requestAnimationFrame(this.animate)

  // 正方体旋转

  this.mesh.rotation.y += 0.02

  this.mesh.rotation.x += 0.01

  // 场景旋转

  this.scene.rotation.y += 0.01

  this.renderer.render(this.scene, this.camera)

}

```

#### 第九步

> 启用场景控制器

```js

controlsFn () {

  // tslint:disable-next-line

  this.controls = new OrbitControls(this.camera, this.renderer.domElement)

},

```

####  controls 知识点

```js

controls.enablePan = false; //禁止右键拖拽

controls.enableZoom = false;//禁止缩放

controls.enableRotate = false; //禁止旋转

controls.minZoom = 0.5; // 最小缩放比例

controls.maxZoom = 2; // 放大最大比例

// 上下旋转范围

controls.minPolarAngle = 0;

controls.maxPolarAngle = Math.PI;

// 左右旋转范围

controls.minAzimuthAngle = -Math.PI * (100 / 180);

controls.maxAzimuthAngle = Math.PI * (100 / 180);

//将其设为true,以自动围绕目标旋转。请注意,如果它被启用,你必须在你的动画循环里调用.update()。

controls.autoRotate = true

// 当.autoRotate为true时,围绕目标旋转的速度将有多快,默认值为2.0,相当于在60fps时每旋转一周需要30秒。

controls.autoRotateSpeed = 2

// 当使用键盘按键的时候,相机平移的速度有多快。默认值为每次按下按键时平移7像素。

controls.keyPanSpeed = 7

// 这一对象包含了用于控制相机平移的按键代码的引用。默认值为4个箭头(方向)键。

controls.keys = {

  LEFT: 'ArrowLeft', //left arrow

  UP: 'ArrowUp', // up arrow

  RIGHT: 'ArrowRight', // right arrow

  BOTTOM: 'ArrowDown' // down arrow

}

// 移除所有的事件监听

controls.dispose () 

// 为指定的DOM元素添加按键监听。推荐将window作为指定的DOM元素。

controls.listenToKeyEvents( domElement : HTMLDOMElement ) 

// 更新控制器。必须在摄像机的变换发生任何手动改变后调用,或如果.autoRotate或.enableDamping被设置时,在update循环里调用。

controls.update ()

```

#### 完整代码示例

```js

import Vue from 'vue';

import * as THREE from 'three';

import * as OrbitControls from 'three-orbitcontrols'

interface DataType {

    id: HTMLElement | null | Object | any;

    domW: Number | any;

    domH: Number | any;

    scene: THREE.Scene | null | any;

    camera: THREE.Camera | null | any;

    renderer: THREE.Renderer | null | any;

    mesh: THREE.Mesh | any;

    controls: null | any;

}

export default Vue.extend({

  name: 'ThreeTwo',

  layout: 'threelayout',

  data (): DataType {

    return {

      id: null,

      domW: 0,

      domH: 0,

      scene: null,

      camera: null,

      renderer: null,

      mesh: null,

      controls: null

    }

  },

  mounted () {

    this.id = document.getElementById('threeone')

    this.domW = this.id.offsetWidth

    this.domH = this.id.offsetHeight

    this.init()

  },

  methods: {

    init () {

      this.scene = new THREE.Scene()

      this.camera = new THREE.PerspectiveCamera(45, this.domW / this.domH, 0.01, 20000)

      this.camera.position.z = 800

      // this.camera.position.y = 100

      this.renderer = new THREE.WebGLRenderer({

        antialias: true,

        alpha: true

      })

      this.renderer.setSize(this.domW, this.domH)

      this.id.appendChild(this.renderer.domElement)

      this.addLight()

      this.axisHelper()

      this.initBox()

      this.animate()

      this.onWindowResize()

      this.controlsFn()

    },

    controlsFn () {

      // tslint:disable-next-line

      this.controls = new OrbitControls(this.camera, this.renderer.domElement)

    },

    initBox () {

      const geometry = new THREE.BoxGeometry(200, 200, 200)

      const material = new THREE.MeshBasicMaterial({ color: '#ffffff', map: new THREE.TextureLoader().load('https://www.douchuanwei.com/api/files/img/1.jpeg') })

      this.mesh = new THREE.Mesh(geometry, material)

      this.scene.add(this.mesh)

      const geometry2 = new THREE.SphereGeometry(60, 20, 60)

      const material2 = new THREE.MeshLambertMaterial({

        color: 'red',

        wireframe: true

        // emissive:0xad1919,

        // vertexColors: THREE.NoColors

        // specular:0x4488ee,

        // shininess: 12

      })

      const mesh2 = new THREE.Mesh(geometry2, material2)

      mesh2.translateX(250)

      this.scene.add(mesh2)

      const geometry3 = new THREE.SphereGeometry(60, 20, 60)

      const material3 = new THREE.MeshLambertMaterial({

        color: 'red',

        wireframe: true

        // emissive:0xad1919,

        // vertexColors: THREE.NoColors

        // specular:0x4488ee,

        // shininess: 12

      })

      const mesh3 = new THREE.Mesh(geometry3, material3)

      mesh3.translateX(-250)

      this.scene.add(mesh3)

    },

    addLight () {

      const ambientLight = new THREE.AmbientLight('#ffffff')

      this.scene.add(ambientLight)

      const light = new THREE.DirectionalLight('#ffffff')

      this.scene.add(light)

      const pointLight = new THREE.PointLight('#ffffff', 0.1, 1000)

      pointLight.position.set(300, 300, 300)

      this.scene.add(pointLight)

    },

    axisHelper () {

      const axes:THREE.AxesHelper = new THREE.AxesHelper(800)

      this.scene.add(axes)

    },

    onWindowResize () {

      window.onresize = () => {

        this.domH = this.id.offsetHeight

        this.domW = this.id.offsetWidth

        this.camera.aspect = this.domW / this.domH

        this.camera.updateProjectionMatrix()

        this.renderer.setSize(this.domW, this.domH)

      }

    },

    animate () {

      window.requestAnimationFrame(this.animate)

      this.mesh.rotation.y += 0.02

      this.mesh.rotation.x += 0.01

      this.scene.rotation.y += 0.01

      this.renderer.render(this.scene, this.camera)

    }

  }

});

```

```

[更多内容请到小豆包》](https://www.douchuanwei.com/)

> 扫码访问小豆包

![23_34de43370a343405db1b00359bb895cd.png](https://www.douchuanwei.com/api/files/2022-03-05/png/23_34de43370a343405db1b00359bb895cd.png)

### 扫码关注小豆包公众号

![小豆包公众号.jpg](https://www.douchuanwei.com/api/files/2022-03-05/jpeg/小豆包公众号.jpg)

你可能感兴趣的:(第二课threejs模型场景控制器)