<template>
<div>
<div class="colors">
<span @click="selectColor(index)" class="item"
v-for="(item,index) in colors"
:style="{backgroundColor:item.value}">{
{item.name}}</span>
</div>
<div class="material">
<span @click="selectMeterial(index)" class="material-item"
v-for="(item,index) in materials"
:style="{backgroundColor:item.value}">{
{item.name}}</span>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import * as THREE from "three"
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls"
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader"
import {DRACOLoader} from "three/examples/jsm/loaders/DRACOLoader"
const scene=new THREE.Scene()
//相机
const camara=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)
camara.position.set(1,4,10)
//平面
const grid=new THREE.GridHelper(30,30)
scene.add(grid)
//颜色数据
const colors=[
{name:"粉色",value:"#f8c6fd"},
{name:"亮红",value:"#f00"},
{name:"天蓝",value:"#84bbeb"},
{name:"紫色",value:"#ac84eb"},
]
//材质
const materials=[
{name:"磨砂",value:1},
{name:"烤漆",value:0},
]
//几何体
// const cube=new THREE.Mesh(
// new THREE.BoxGeometry(2,2,2),
// new THREE.MeshBasicMaterial({color:"#f90"})
// )
// cube.position.set(0,1,0)
// scene.add(cube)
//创建材质
let bodyMaterial=new THREE.MeshPhysicalMaterial({
color:"#f00",
metalness:1,
roughness:0.5,
clearcoat:1,
clearcoatRoughness:0
})
let frontMaterial=new THREE.MeshPhysicalMaterial({
color:"#f00",
metalness:1,
roughness:0.5,
clearcoat:1,
clearcoatRoughness:0
})
let hoodMaterial=new THREE.MeshPhysicalMaterial({
color:"#f00",
metalness:1,
roughness:0.5,
clearcoat:1,
clearcoatRoughness:0
})
let wheelMaterial=new THREE.MeshPhysicalMaterial({
color:"#f00",
metalness:1,
roughness:0.1,
})
let glassMaterial=new THREE.MeshPhysicalMaterial({
color:"#fff",
metalness:0,
roughness:0.1,
transmission:1,
transparent:true
})
//加载模型
const loader=new GLTFLoader()
const dracoLoader=new DRACOLoader()
dracoLoader.setDecoderPath("public/draco/")
loader.setDRACOLoader(dracoLoader)
loader.load("model/bmw01.glb",(texture)=>{
let bmw=texture.scene
bmw.traverse((child)=>{
if(child.isMesh&&child.name.includes("轮毂")){
wheels.push(child)
child.material=wheelMaterial
}
//车身
if(child.isMesh&&child.name.includes("Mesh002")){
carBody=child
carBody.material=bodyMaterial
}
//前脸
if(child.isMesh&&child.name.includes("前脸")){
frontCar=child
frontCar.material=frontMaterial
}
//引擎盖1
if(child.isMesh&&child.name.includes("引擎盖")){
hoodCar=child
hoodCar.material=hoodMaterial
}
//挡风玻璃
if(child.isMesh&&child.name.includes("挡风玻璃")){
glassCar=child;
glassCar.material= glassMaterial
}
})
scene.add(bmw)
})
//光源
let light1=new THREE.DirectionalLight("#fff",1)
light1.position.set(0,0,10)
scene.add(light1)
let light2=new THREE.DirectionalLight("#fff",1)
light2.position.set(0,0,-10)
scene.add(light2)
let light3=new THREE.DirectionalLight("#fff",1)
light3.position.set(-10,0,0)
scene.add(light3)
let light4=new THREE.DirectionalLight("#fff",1)
light4.position.set(0,10,0)
scene.add(light4)
let light5=new THREE.DirectionalLight("#fff",0.3)
light5.position.set(0,-10,0)
scene.add(light5)
let light6=new THREE.DirectionalLight("#fff",0.3)
light6.position.set(5,10,0)
scene.add(light6)
let light7=new THREE.DirectionalLight("#fff",0.3)
light7.position.set(0,10,5)
scene.add(light7)
let light8=new THREE.DirectionalLight("#fff",1)
light8.position.set(-5,10,5)
scene.add(light8)
//
let wheels=[]
let carBody,frontCar,hoodCar,glassCar
//渲染器
const renderder=new THREE.WebGLRenderer({
antialias:true
})
renderder.setSize(window.innerWidth,window.innerHeight)
renderder.setClearColor("#ccc")
document.body.appendChild(renderder.domElement)
//控制器
const control=new OrbitControls(camara,renderder.domElement)
//动画
//渲染函数
const render=()=>{
renderder.render(scene,camara)
requestAnimationFrame(render)
}
render()
window.addEventListener("resize",()=>{
camara.aspect=window.innerWidth/window.innerHeight;
camara.updateProjectionMatrix()
})
const selectColor=(index)=>{
console.log("colors[index]:",index)
// bodyMaterial.color.set(colors[index].value.value)
// frontMaterial.color.set(colors[index].value.value)
// hoodMaterial.color.set(colors[index].value.value)
bodyMaterial.color.set(colors[index].value)
frontMaterial.color.set(colors[index].value)
hoodMaterial.color.set(colors[index].value)
}
const selectMeterial=(index)=>{
console.log("material[index]:",index)
bodyMaterial.clearcoatRoughness=materials[index].value
frontMaterial.clearcoatRoughness=materials[index].value
hoodMaterial.clearcoatRoughness=materials[index].value
}
</script>
<style scoped>
.a{
color:#ac84eb
}
.colors{
width: 600px;
position:absolute;
top:20px;
right:0;
z-index: 10;
display: flex;
justify-content: flex-end;
padding-right:20px
}
.item{
display: inline-block;
padding: 3px 10px;
margin-left:6px;
text-align: center;
color:#fff;
border-radius:24px;
}
.material{
width: 600px;
position:absolute;
top:60px;
right:0;
z-index: 10;
display: flex;
justify-content: flex-end;
padding-right:20px
}
.material-item{
display: inline-block;
padding: 3px 10px;
margin-left:6px;
text-align: center;
background:#333;
color:#fff;
border-radius:24px;
}
</style>
这里有一点要注意:就是载入模型的路径问题:
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("public/");
dracoLoader.preload();
loader.setDRACOLoader(dracoLoader);
loader.load("bmw01.glb", glb => {
console.log("glb", glb);
mesh = new THREE.Mesh(glb, new THREE.MeshStandardMaterial({ color: "#fff" }));
scene.add(mesh);
renderder.render(scene, camara);
});
本案例中public文件夹下存在四个文件,分别是draco_decoder,draco_decoder.wasm,draco_encoder.js,draco_wasm_wrapper.js,他们用来解析模型,一定要注意这四个文件一定要放到dracoLoader.setDecoderPath("");的目录下。特别注意,这里的是setDecoderPath()而不是setPath(),之前就是因为不小心自动补全写成了setPath导致模型加载一直报404,如果设置解析的目录dracoLoader.setDecoderPath("public/model");那么这四个文件就必须要在public/model目录下,第二点:注意这四个文件的版本与当前项目的three.js版本是否一致。否则会无法解析。最好的办法是安装最新的three.js包。同时在three.js的github找到dev分支找到exa,ples/jsm/libs/draco目录,抽取该目录下的四个js文件,也就是draco_decoder,draco_decoder.wasm,draco_encoder.js,draco_wasm_wrapper.js,放到dracoLoader.setDecoderPath("");所设置的目录下,