使用vue学习three.js之加载和使用纹理-使用CubeCamera创建反光效果,动态环境贴图实现,立方体全景贴图

Posted 点燃火柴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用vue学习three.js之加载和使用纹理-使用CubeCamera创建反光效果,动态环境贴图实现,立方体全景贴图相关的知识,希望对你有一定的参考价值。

1.demo效果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2. 实现要点

2.1 创建立方体相机CubeCamera

创建立方体的语法如下

const cubeCamera = new THREE.CubeCamera( near, far, cubeRenderTarget)

参数说明

  • near – 远剪切面的距离
  • far – 近剪切面的距离
  • cubeRenderTarget – 立方体渲染器目标对象
    如上参数可知创建CubeCamera对象需要三个参数,其中第三个参数是一个WebGLCubeRenderTarget 类型的对象,所以需要首先创建这样一个对象,然后创建立方体对象,具体代码如下:
//创建立方体渲染器目标对象
this.cubeRenderTarget = new THREE.WebGLCubeRenderTarget(128, {
  format: THREE.RGBFormat,
  generateMipmaps: true,
  minFilter: THREE.LinearMipmapLinearFilter
})

//创建立方体相机
this.cubeCamera = new THREE.CubeCamera(1, 100000, this.cubeRenderTarget)
this.scene.add(this.cubeCamera)

2.2 使用动态环境贴图材质

上一步中我们创建完立方体相机后,立方体渲染器目标对象上边生成了有相机获取的图形生成的纹理,并保存在cubeRenderTarget.texture之中,接下来把它当环境贴图创建材质,随后使用这个材质创建一个球体Mesh

//创建球体
this.renderer.renderTarget
const dynamicEnvMapMaterial = new THREE.MeshPhongMaterial({
  envMap: this.cubeRenderTarget.texture
})
const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)
this.sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMapMaterial)
this.scene.add(this.sphere)

2.3 render中更新立方体相机

this.cubeCamera.update(this.renderer, this.scene) //立方体相机更新

通过以上三步就可以实现将场景中除球体以外的所有模型作为环境贴图添加到球体上,支持动态变化,除此之外还有几点需要说明一下,具体详见以下步骤

2.4 创建场景的全景贴图

这一步与上一篇文章一样,代码如下

// 创建场景
createScene() {
  this.scene = new THREE.Scene()
  const publicPath = process.env.BASE_URL
  //创建全景贴图设置为场景背景
  this.scene.background = new THREE.CubeTextureLoader()
    .setPath(`${publicPath}textures/cubemap/parliament/`)
    .load([
      'posx.jpg',
      'negx.jpg',
      'posy.jpg',
      'negy.jpg',
      'posz.jpg',
      'negz.jpg'
    ])
}

2.5 创建场景中的模型

模型包括一个立方体和一个球体,要注意一下几点

  • 创建静态环境贴图材质
    这里就是使用场景的背景创建环境贴图材质,只需要将场景的背景赋值给材质的envMap即可
  • 创建方块和圆环
    这里使用BoxGeometry创建一个立方体模型,使用TorusGeometry创建一个圆环,它们使用的材质都是刚刚创建的环境贴图材质
  • 创建动态环境贴图的球体
    这里文章中 2.2 已有说明,请直接看代码
// 创建模型
createModels() {
  const material = new THREE.MeshPhongMaterial()
  material.envMap = this.scene.background //场景背景设置为材质的环境贴图

  //创建方块
  const boxGeometry = new THREE.BoxGeometry(15, 15, 15)
  this.cube = new THREE.Mesh(boxGeometry, material)

  this.cube.position.set(-22, 0, 0)
  this.scene.add(this.cube)

  //构建圆环
  const torusGeometry = new THREE.TorusGeometry(8, 3, 16, 100)
  this.torus = new THREE.Mesh(torusGeometry, material)
  this.torus.position.set(22, 0, 0)
  this.scene.add(this.torus)

  //创建球体
  this.renderer.renderTarget
  const dynamicEnvMapMaterial = new THREE.MeshPhongMaterial({
    envMap: this.cubeRenderTarget.texture
  })
  const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)
  this.sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMapMaterial)
  this.scene.add(this.sphere)
}

3. demo代码

<template>
  <div>
    <div id="container" />
    <div class="controls-box">
      <section>
        <el-row>
          <el-checkbox v-model="properties.rotate">
            rotate
          </el-checkbox>
        </el-row>
        <el-row>
          <div v-for="(item,key) in properties" :key="key">
            <div v-if="item&&item.name!=undefined">
              <el-col :span="8">
                <span class="vertice-span">{{ item.name }}</span>
              </el-col>
              <el-col :span="13">
                <el-slider v-model="item.value" :min="item.min" :max="item.max" :step="item.step" :format-tooltip="formatTooltip" @change="propertiesChange" />
              </el-col>
              <el-col :span="3">
                <span class="vertice-span">{{ item.value }}</span>
              </el-col>
            </div>
          </div>
        </el-row>
        <el-row>
          <el-col :span="8" class="label-col">
            <label>texture</label>
          </el-col>
          <el-col :span="16">
            <el-select v-model="properties.textureType" placeholder="请选择" @change="propertiesChange">
              <el-option v-for="item in texturesOptions" :key="item.value" :label="item.label" :value="item.value" />
            </el-select>
          </el-col>
        </el-row>
      </section>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
export default {
  data() {
    return {
      texturesOptions: [
        {
          value: 'bathroom',
          label: 'bathroom'
        },
        {
          value: 'plaster',
          label: 'plaster'
        },
        {
          value: 'metal-floor',
          label: 'metal-floor'
        },
        {
          value: 'none',
          label: 'none'
        }
      ],
      properties: {
        normalScale: {
          name: 'normalScale',
          value: 1,
          min: -2,
          max: 2,
          step: 0.1
        },
        reflectivity: {
          name: 'reflectivity',
          value: 1,
          min: 0,
          max: 2,
          step: 0.1
        },
        textureType: 'none',
        rotate: false
      },
      cube: null,
      sphere: null,
      torus: null,
      camera: null,
      cubeCamera: null,
      cubeRenderTarget: null,
      scene: null,
      renderer: null,
      controls: null
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    formatTooltip(val) {
      return val
    },

    // 初始化
    async init() {
      this.createScene() // 创建场景
      await this.createRender() // 创建渲染器
      this.createCamera() // 创建相机
      this.createLight() // 创建光源
      this.createModels() // 创建模型

      this.createControls() // 创建控件对象

      this.render() // 渲染
    },
    // 创建场景
    createScene() {
      this.scene = new THREE.Scene()
      const publicPath = process.env.BASE_URL
      //创建全景贴图设置为场景背景
      this.scene.background = new THREE.CubeTextureLoader()
        .setPath(`${publicPath}textures/cubemap/parliament/`)
        .load([
          'posx.jpg',
          'negx.jpg',
          'posy.jpg',
          'negy.jpg',
          'posz.jpg',
          'negz.jpg'
        ])
    },
    // 创建模型
    createModels() {
      const material = new THREE.MeshPhongMaterial()
      material.envMap = this.scene.background //场景背景设置为材质的环境贴图

      //创建方块
      const boxGeometry = new THREE.BoxGeometry(15, 15, 15)
      this.cube = new THREE.Mesh(boxGeometry, material)

      this.cube.position.set(-22, 0, 0)
      this.scene.add(this.cube)

      //构建圆环
      const torusGeometry = new THREE.TorusGeometry(8, 3, 16, 100)
      this.torus = new THREE.Mesh(torusGeometry, material)
      this.torus.position.set(22, 0, 0)
      this.scene.add(this.torus)

      //创建球体
      this.renderer.renderTarget
      const dynamicEnvMapMaterial = new THREE.MeshPhongMaterial({
        envMap: this.cubeRenderTarget.texture
      })
      const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)
      this.sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMapMaterial)
      this.scene.add(this.sphere)
    },

    // 创建光源
    createLight() {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff) // 创建环境光
      this.scene.add(ambientLight) // 将环境光添加到场景

      const spotLight = new THREE.SpotLight(0xffffff) // 创建聚光灯
      spotLight.position.set(0, 50, 50)
      spotLight.intensity = 2.2
      this.scene.add(spotLight)
    },

    // 创建相机
    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(0, 12, 68) // 设置相机位置

      this.camera.lookAt(new THREE.Vector3(0, 0, 0)) // 设置相机方向
      this.scene.add(this.camera)
      const renderTarget = this.renderer.getRenderTarget()

      //创建立方体渲染器目标对象
      this.cubeRenderTarget = new THREE.WebGLCubeRenderTarget(128, {
        format: THREE.RGBFormat,
        generateMipmaps: true,
        minFilter: THREE.LinearMipmapLinearFilter
      })

      //创建立方体相机
      this.cubeCamera = new THREE.CubeCamera(1, 100000, this.cubeRenderTarget)
      this.scene.add(this.cubeCamera)
    },
    // 创建渲染器
    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(0xeeeeee, 1) // 设置背景颜色
      element.appendChild(this.renderer.domElement)
    },

    propertiesChange() {
      const publicPath = process.env.BASE_URL
      //如果不为none为方块加载纹理贴图
      if (this.properties.textureType !== 'none') {
        const texture = new THREE.TextureLoader().load(
          `${publicPath}textures/general/` +
            this.properties.textureType +
            '.jpg'
        )
        this.cube.material.map = texture

        const normal = new THREE.TextureLoader().load(
          `${publicPath}textures/general/` +
            this.properties.textureType +
            '-normal.jpg'
        )

        this.cube.material.normalMap = normal

        // 更新法线缩放
        this.cube.material.normalScale.set(
          this.properties.normalScale.value,
          this.properties.normalScale.value
        ) // normalScale(x,y)
      } else {
        this.cube.material = new THREE.MeshPhongMaterial({
          envMap: this.scene.background
        })
      }

      // 克隆方块材质赋值给圆环材质
      this.torus.material = this.cube.material.clone()

      //更新模型的材质折射率
      this.cube.material.reflectivity = this.properties.reflectivity.value
      this.torus.material.reflectivity = this.properties.reflectivity.value

      //更新材质中的纹理
      this.cube.material.needsUpdate = true
      this.torus.material.needsUpdate 

以上是关于使用vue学习three.js之加载和使用纹理-使用CubeCamera创建反光效果,动态环境贴图实现,立方体全景贴图的主要内容,如果未能解决你的问题,请参考以下文章

使用vue学习three.js之加载和使用纹理-用视频输出作为纹理,使用VideoTexture视频纹理实现物体表面播放视频

使用vue学习three.js之加载和使用纹理- 通过设置纹理的wrapSwrapTrepeat属性实现纹理的重复平铺,纹理的重复映射

使用vue学习three.js之加载和使用纹理-使用canvas画布上的绘画作为纹理渲染到方块上,使用动态绘画纹理

使用vue学习three.js之加载和使用纹理-设置material.bumpMap属性使用凹凸贴图创建皱纹

使用vue学习three.js之加载和使用纹理-在canvas画布上生成噪音图,然后创建凹凸贴图

使用vue学习three.js之加载和使用纹理-使用CubeCamera创建反光效果,动态环境贴图实现,立方体全景贴图