当前位置:   article > 正文

three.js学习使用Scene对象,在三维空间中创建随机大小的立方体(vue中使用three.js03)_scene.traverse

scene.traverse

一、demo效果总览

在这里插入图片描述
如上图所示,demo有以下几个功能

  1. 通过addCube按钮添加随机色彩、随机大小、随机位置的方块在底板上
  2. 可以通过removeCube按钮依次移除方块
  3. 可以通过printScene按钮在console后台打印scene对象
  4. 可以通过rotationSpeed滑块调节方块旋转的速度
  5. 可以通过fogValue滑块调节雾化的值查看效果

二、scene对象相关的方法和属性

1.给场景中添加物体 Scene.add(object)

demo中大量用到add方法,该方法可以给场景中添加物体,其本质是给scene对象的children属性中添加加对象,已通过代码验证,验证过程如下

 // 将生成的方块添加到场景
 //方式一
 this.scene.add(cube)
 
 //方式二
 this.scene.children.push(cube)  
 //this.scene.children.push(cube) 与 this.scene.add(cube) 一样的效果 也说明scene.add()方法操作的本质就是给scene对象中children属性中添加对象

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.从场景中移除物体 Scene.remove(obj)

该方法主要是从场景中删除物体,本质也一样是从scene对象中children属性移除对象,demo中移除方块的函数可以通过一行代码替代,请参阅以下代码

// 删除一个方块
  removeCube () {
    const allChildren = this.scene.children
    const lastChildren = allChildren[allChildren.length - 1]
    if (lastChildren instanceof THREE.Mesh) {
      this.scene.remove(lastChildren)
    }
  }
//上面这个函数可直接用如下代码替换
this.scene.children.pop() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.从场景中查找物体 Scene.getChildByName(name)

该方法是通过对象名称查找场景中的物体,demo中没有用的此方法,不对今后会有机会用到,暂且储备起来,使用的方式很简单只需要传入一个简单的name参数,到这里你是不是也想到另外一种替代的方式呢,是的,通过数组查找的方法去scene对象的children中去查找,不过这样做反而会增加代码量,个人推荐还是使用scene对象提供的方法

4.遍历场景中的物体 Scene.traverse(function)

该方法会变量场景对象中的每个物体,参数是一个回调函数,我们可以依次访问每一个场景中的对象,同样在这里做一些处理,是不是想到一个数组的方法几乎一样的功能,对,就是你了 forEach,不过在使用时要注意this指向,请看以下例子

const THIS = this
 THIS.scene.traverse(function (e) {
   if (e instanceof THREE.Mesh && e !== THIS.plane) {
     e.rotation.x += THIS.rotationSpeed / 100
     e.rotation.y += THIS.rotationSpeed / 100
     e.rotation.z += THIS.rotationSpeed / 100
   }
 })

//traverse函数完全可以用forEach函数替代,效果一样,代码几乎雷同,只不过是用scene对象的children属性获取了所有成员列表
THIS.scene.children.forEach(function (e) {
   if (e instanceof THREE.Mesh && e !== THIS.plane) {
     e.rotation.x += THIS.rotationSpeed / 100
     e.rotation.y += THIS.rotationSpeed / 100
     e.rotation.z += THIS.rotationSpeed / 100
   }
 })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5.获取场景中的物体 Scene.children

children属性就不用做过多介绍了,就是返回场景中所有子对象的列表,我们在demo中点击一下printScene按钮,看看console.log (点击按钮前添加了三个方块)
在这里插入图片描述

在这里插入图片描述

6.给场景设置雾化效果 Scene.fog

雾化属性很简单就是给场景添加雾化效果,这里介绍两个雾化函数吧

Fog函数

使用方式:fog = new THREE.Fog( [name,]color, near, far )
参数说明:

  1. name : 对象的名称,可选、不必唯一。默认值是一个空字符串。
  2. color :雾的颜色。比如说,如果将其设置为黑色,远处的物体将被渲染成黑色。
  3. near : 开始应用雾的最小距离。默认值是1。
  4. far :结束计算、应用雾的最大距离,距离大于活动摄像机“far”个单位的物体将不会被雾所影响。默认值是1000。

FogExp2

使用方式:fog = new THREE.FogExp2( [name,]color, density )
参数说明:

  1. name : 对象的名称,可选、不必唯一。默认值是一个空字符串。
  2. density :定义雾的密度将会增长多块。默认值是0.00025。

顺便贴一下demo中的代码

// 添加雾化效果
  addFog () {
     //使用Fog创建雾化
    // this.scene.fog = new THREE.Fog(0xefefef, 0.15, 100)
    //使用FogExp2创建雾化
    this.scene.fog = new THREE.FogExp2(0xffffff, this.fogValue / 1000)
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

7.统一场景中物体的材质 Scene.overrideMaterial

可以通过这个属性强制场景中的所有物体都使用相同的材质

三、demo代码

<template>
  <div>
    <div id="container"></div>
    <div class="controls-box">
      <span class="demonstration">rotationSpeed</span>
      <el-slider v-model="rotationSpeed" :max="50" :format-tooltip="formatTooltip">
      </el-slider>
      <span class="demonstration">fogValue</span>
      <el-slider v-model="fogValue" :max="50" :format-tooltip="formatFogTooltip">
      </el-slider>
      <br>
      <el-button type="primary" class="controls-button" size="mini" @click="addCube">addCube</el-button>
      <el-button type="primary" class="controls-button" size="mini" @click="removeCube">removeCube</el-button>
      <el-button type="primary" class="controls-button" size="mini" @click="outputObjects">printScene</el-button>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
export default {
  data () {
    return {
      rotationSpeed: 2,
      fogValue: 2,
      camera: null,
      scene: null,
      renderer: null,
      planeGeometry: null,
      plane: null,
      controls: null
    }
  },
  mounted () {
    this.init()
  },
  methods: {
    formatTooltip (val) {
      return val / 100
    },
    formatFogTooltip (val) {
      return val / 1000
    },
    // 初始化
    init () {
      this.createScene() // 创建场景
      this.createMesh() // 创建网格模型
      this.createLight() // 创建光源
      this.createCamera() // 创建相机
      this.createRender() // 创建渲染器
      this.createControls() // 创建控件对象
      this.addFog() // 添加雾化效果
      this.render() // 渲染
    },
    // 创建场景
    createScene () {
      this.scene = new THREE.Scene()
    },
    // 创建网格模型
    createMesh () {
      this.planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1) // 创建一个平面对象PlaneGeometry
      const planeMaterial = new THREE.MeshLambertMaterial({
        color: 0xffffff
      }) // 材质对象Material
      this.plane = new THREE.Mesh(this.planeGeometry, planeMaterial)
      this.plane.receiveShadow = true

      // 设置平面位置
      this.plane.rotation.x = -0.5 * Math.PI
      this.plane.position.set(0, 0, 0)

      // 平面对象添加到场景中
      this.scene.add(this.plane)
    },
    // 创建光源
    createLight () {
      // 添加聚光灯
      const spotLight = new THREE.SpotLight(0xffffff)
      spotLight.position.set(-40, 60, -10)
      spotLight.castShadow = true
      this.scene.add(spotLight) // 聚光灯添加到场景中
      // 环境光
      const ambientLight = new THREE.AmbientLight(0x0c0c0c)
      this.scene.add(ambientLight)
    },
    // 创建相机
    createCamera () {
      const element = document.getElementById('container')
      const width = element.clientWidth // 窗口宽度
      const height = element.clientHeight // 窗口高度
      const k = width / height // 窗口宽高比
      // PerspectiveCamera( fov, aspect, near, far )
      this.camera = new THREE.PerspectiveCamera(45, k, 0.1, 1000)

      this.camera.position.set(-30, 40, 30) // 设置相机位置
      this.camera.lookAt(this.scene.position) // 设置相机方向
      this.scene.add(this.camera)
    },
    // 创建渲染器
    createRender () {
      const element = document.getElementById('container')
      this.renderer = new THREE.WebGLRenderer()
      this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
      this.renderer.setClearColor(0x3f3f3f, 1) // 设置背景颜色
      this.renderer.shadowMapEnabled = true
      element.appendChild(this.renderer.domElement)
    },
    render () {
      const THIS = this
      THIS.scene.traverse(function (e) {
        if (e instanceof THREE.Mesh && e !== THIS.plane) {
          e.rotation.x += THIS.rotationSpeed / 100
          e.rotation.y += THIS.rotationSpeed / 100
          e.rotation.z += THIS.rotationSpeed / 100
        }
      })

      // THIS.scene.traverse(fun) 与 THIS.scene.children.forEach(fun) 是一样的功能都是去遍历scene对象的成员
      /* THIS.scene.children.forEach(function (e) {
        if (e instanceof THREE.Mesh && e !== THIS.plane) {
          e.rotation.x += THIS.rotationSpeed / 100
          e.rotation.y += THIS.rotationSpeed / 100
          e.rotation.z += THIS.rotationSpeed / 100
        }
      }) */
      this.addFog()
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    },
    // 创建控件对象
    createControls () {
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    },
    // 给平面中添加方块
    addCube () {
      const cubeSize = Math.ceil(Math.random() * 3)
      const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize)
      const cubeMaterial = new THREE.MeshLambertMaterial({
        color: Math.random() * 0xffffff
      })
      const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
      cube.castShadow = true
      cube.name = 'cube-' + this.scene.children.length

      // 给方块设置随机坐标
      cube.position.x =
        -30 + Math.round(Math.random() * this.planeGeometry.parameters.width)
      cube.position.y = Math.round(Math.random() * 5)
      cube.position.z =
        -20 + Math.round(Math.random() * this.planeGeometry.parameters.height)
      // 将生成的方块添加到场景
      this.scene.add(cube)
      // this.scene.children.push(cube)  //与 this.scene.add(cube) 一样的效果 也是scene.add()操作的本质
    },
    // 删除一个方块
    removeCube () {
      const allChildren = this.scene.children
      const lastChildren = allChildren[allChildren.length - 1]
      if (lastChildren instanceof THREE.Mesh) {
        this.scene.remove(lastChildren)
      }
      // this.scene.children.pop() //整个removeCube函数其实就是做这个操作
    },
    // 打印scene对象子元素
    outputObjects () {
      console.log(this.scene)
    },

    // 添加雾化效果
    addFog () {
      // this.scene.fog = new THREE.Fog(0xefefef, 0.15, 100)
      this.scene.fog = new THREE.FogExp2(0xffffff, this.fogValue / 1000)
    }
  }
}
</script>

<style>
#container {
  position: absolute;
  width: 100%;
  height: 100%;
}
.controls-box {
  position: absolute;
  right: 5px;
  top: 5px;
  width: 300px;
  height: 180px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #c3c3c3;
}
.controls-button {
  margin: 3px 0px;
}
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/95977
推荐阅读
相关标签
  

闽ICP备14008679号