🌟前言
哈喽小伙伴们,最近工作比较忙一直没有给大家更新,新的专栏 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>
🌟写在最后
更多Three知识以及API请大家持续关注,尽请期待。各位小伙伴让我们 let’s be prepared at all times!