目录
  • 🌟前言
  • 🌟先看效果
  • 🌟实现代码
  • 🌟写在最后


🌟前言

哈喽小伙伴们,最近工作比较忙一直没有给大家更新,新的专栏 Three.js第三篇,记录一下博主学习Three.js的过程;一起来看下吧。

🌟先看效果


Three-3D车模换肤


🌟实现代码

<template>
  <div>
    <div ref="canvas" class="canvas" />
    <div class="car-color">
      <div class="color1">
        <div class="color-blue2" @click="setCarColor('#2e4e61')" />
        <span>天际蓝</span>
      </div>
      <div class="color1">
        <div class="color-white" @click="setCarColor('#c0c0c0')" />
        <span>亮银色</span>
      </div>
      <div class="color1">
        <div class="color-blank" @click="setCarColor('#222')" />
        <span>星际黑</span>
      </div>
      <div class="color1">
        <div class="color-red" @click="setCarColor('#ff0000')" />
        <span>中国红</span>
      </div>
      <div class="color1">
        <div class="color-green" @click="setCarColor('#9dc209')" />
        <span>苹果绿</span>
      </div>
      <div class="color1">
        <div class="color-blue" @click="setCarColor('#2443e2')" />
        <span>雪邦蓝</span>
      </div>
    </div>
  </div>

</template>

<script>
import * as THREE from 'three'
import { dracoLoader } from './dracoLoader.js'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 定义模型初始材质
const bodyMaterial = new THREE.MeshPhysicalMaterial({
  color: '#2e4e61',
  metalness: 1,
  roughness: 0.5,
  clearcoat: 1.0,
  clearcoatRoughness: 0.03
})
export default {
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      animationMixer: null,
      clock: null
    }
  },
  computed: {},
  watch: {},
  mounted() {
    this.initThree()
  },
  methods: {
    initThree() {
      // 创建场景
      this.scene = new THREE.Scene()
      // 创建天空盒
      const path = '/skybox1/'
      const urls = [
        path + '6.png',
        path + '3.png',
        path + '2.png',
        path + '1.png',
        path + '5.png',
        path + '4.png'
      ]
      const textCube = new THREE.CubeTextureLoader().load(urls)
      // textCube.encoding = THREE.sRGBEncoding
      this.scene.background = textCube

      // 创建相机  透视相机
      // fov:角度  aspect:宽高比  near:近端  far:远端
      this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000)
      // 设置相机位置
      this.camera.position.set(-20, 20, -44)
      this.scene.add(this.camera)
      // 创建地面
      const floorMat = new THREE.MeshStandardMaterial({
        color: 0xa9a9a9 // 材质的颜色
      })
      const floorGeometry = new THREE.BoxGeometry(300, 300, 0.01, 1, 1, 1)
      const floorMesh = new THREE.Mesh(floorGeometry, floorMat)
      floorMesh.receiveShadow = true
      floorMesh.rotation.x = -Math.PI / 2.0
      this.scene.add(floorMesh)

      this.animationMixer = new THREE.AnimationMixer(this.scene) // 常见动画混合器
      // 时钟
      this.clock = new THREE.Clock()

      // 给场景增加环境光
      // 设置环境光
      this.scene.add(new THREE.AmbientLight(0xffffff, 0.5))
      // 添加球光源
      const hesLight = new THREE.HemisphereLight(0xffffff, 0x444444)
      hesLight.intensity = 0.6
      this.scene.add(hesLight)
      // 自然光
      // const dirLight = new THREE.DirectionalLight()
      // dirLight.position.set(0, 0, 15)
      // this.scene.add(dirLight)
      const dirLight2 = new THREE.DirectionalLight()
      dirLight2.position.set(0, 0, -15)
      this.scene.add(dirLight2)
      const dirLight3 = new THREE.DirectionalLight()
      dirLight3.position.set(15, 0, 0)
      this.scene.add(dirLight3)
      const dirLight4 = new THREE.DirectionalLight()
      dirLight4.position.set(-15, 0, 0)
      this.scene.add(dirLight4)
      const dirLight5 = new THREE.DirectionalLight()
      dirLight5.position.set(0, 15, 0)
      this.scene.add(dirLight5)
      const dirLight6 = new THREE.DirectionalLight()
      dirLight6.position.set(0, -15, 0)
      this.scene.add(dirLight6)
      const dirLight7 = new THREE.DirectionalLight()
      dirLight7.position.set(5, 15, 5)
      this.scene.add(dirLight7)
      const dirLight8 = new THREE.DirectionalLight()
      dirLight8.position.set(-5, -15, -5)
      this.scene.add(dirLight8)
      // 聚光灯
      const sportLight = new THREE.SpotLight(0xffffff, 0.8)
      sportLight.angle = Math.PI / 8 // 散射角度,跟水平线的夹角
      sportLight.penumbra = 0.1 // 聚光锥的半影衰减百分比
      sportLight.decay = 2 // 纵向:沿着光照距离的衰减量。
      sportLight.distance = 10
      sportLight.shadow.radius = 10
      // 阴影映射宽度,阴影映射高度
      sportLight.shadow.mapSize.set(512, 512)
      sportLight.position.set(0, 15, 0)
      // 光照射的方向
      sportLight.target.position.set(0, 0, 0)
      sportLight.castShadow = true
      this.scene.add(sportLight)
      // 加载模型
      const modelUrl = '/3DModel/911-transformed.glb' // 定义所使用模型路径路径
      dracoLoader(modelUrl)
        .then((res) => {
          // console.log(res.scene)
          res.scene.name = '3dmodel'
          res.scene.traverse(function(child) {
            // console.log(child)
            if (child.isMesh) {
              child.frustumCulled = false
              // 模型阴影
              child.castShadow = true
              // 模型自发
              child.material.emissive = child.material.color
              child.material.emissiveMap = child.material.map
            }
            // 获取不同部位
            if (child.isMesh && child.name.indexOf('boot') !== -1 && child.name.indexOf('boot004') === -1) {
              child.material = bodyMaterial
            }
          })
          res.scene.scale.set(13, 13, 13)
          res.scene.rotateY(Math.PI)
          res.scene.rotation.z = Math.PI
          res.scene.position.set(0, 9, 0)
          this.scene.add(res.scene)
        })
        .catch((err) => {
          console.log(err)
        })

      // 初始化渲染器
      this.renderer = new THREE.WebGLRenderer()
      this.renderer.shadowMap.enabled = true
      this.renderer.antialias = true
      // 设置渲染的尺寸大小
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      this.renderer.setClearColor(0xffffff, 1.0)
      // 监听屏幕大小的改变,修改渲染器的宽高和相机的比例:
      window.addEventListener('resize', () => {
        this.renderer.setSize(window.innerWidth, window.innerHeight)
        this.camera.aspect = window.innerWidth / window.innerHeight
        this.camera.updateProjectionMatrix()
      })

      // 将webgl渲染的canvas内容添加到body上
      this.$refs.canvas.appendChild(this.renderer.domElement)

      // 创建轨道控制器
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      // 上下旋转范围
      this.controls.minPolarAngle = 0// 默认值0
      this.controls.maxPolarAngle = Math.PI / 2.1// 默认值Math.PI

      this.controls.enableDamping = true // 开启阻尼
      this.controls.dampingFactor = 0.1
      this.controls.enableZoom = false
      this.controls.addEventListener('change', (event) => {
        console.log(event)
      })
      this.render()
    },
    render() {
      this.controls && this.controls.update()// 每一帧都需要更新
      this.animationMixer.update(this.clock.getDelta()) // 更新动画
      this.renderer.render(this.scene, this.camera)
      // 渲染下一帧的时候就会调用render函数
      requestAnimationFrame(this.render)
    },
    setCarColor(color) {
      console.log(color)
      // 通过点击不同的色块,给初始的模型材质赋值
      bodyMaterial.color.set(color)
    }
  }
}
</script>

<style scoped>
html, body {
  overflow-y: hidden !important;
}

.canvas {
  overflow-y: hidden;
  overflow-x: hidden !important;
}

.car-color {
  /* 设置这个div居中显示 */
  margin: 0 auto;
  position: fixed;
  top: 10%;
  right: -17%;
  width: 40%;
  height: auto;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
}

.color1 {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.color1 div {
  width: 50px;
  height: 50px;
  border-radius: 80px;
  cursor: pointer;
  box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.3);
}
.color1 span {
  color: #000;
}
.color-white {
  background-color: #c0c0c0;
}

.color-blank {
  background-color: #222;
}

.color-red {
  background-color: #FF0000;
}

.color-green {
  background-color: #9dc209;
}

.color-blue {
  background-color: #2443e2;
}
.color-blue2 {
  background-color: #2e4e61;
}

span {
  margin-top: 5px;
}

</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.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.

🌟写在最后

更多Three知识以及API请大家持续关注,尽请期待。各位小伙伴让我们 let’s be prepared at all times!

✨原创不易,还希望各位大佬支持一下!
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!