Threejs进阶之三:通过GUI修改gltf模型(摩托车)颜色
上一节我们对摩托车的场景进行了优化,添加了聚光灯及阴影等效果,这一节我们继续对摩托车场景进行优化,我们通过GUI来控制摩托车各个部位颜色的修改 先看下修改后的最终效果
引入GUI
在motor3d.js中通过import引入GUI插件
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js' //引入GUI
motor03.gltf的组成
在对gltf模型进行修改之前,我们需要先了解下这个模型的组成,我们可以通过在控制台打印该模型的方式查看其文件结构,也可以在threejs官网通过editor功能查看。这里我们通过控制台打印发现该模型一共有8个Mesh组成,我们可以在里面找到哪个Mesh是车身,哪个或哪几个Mesh是车架,然后,我们通过获取这些Mesh来对其颜色进行修改。
创建车身材质
定义一个bodyMaterial变量,用于接收Threejs的材质对象,这里我们使用Threejs提供的物理网关材质MeshPhysicalMaterial,这个材质是基于物理渲染,也就是PBR技术,效果更加逼真,能模拟物体表面的漫反射、镜面反射效果; 先来了解下MeshPhysicalMaterial材质的一些属性 .metalness 金属度属性.metalness表示材质像金属的程度. 非金属材料,如木材或石材,使用0.0,金属使用1.0,中间没有(通常). 默认 0.5. 0.0到1.0之间的值可用于生锈的金属外观。如果还提供了粗糙度贴图.metalnessMap,则两个值都相乘 .roughness 粗糙度属性.roughness材质的粗糙程度. 0.0表示平滑的镜面反射,1.0表示完全漫反射. 默认 0.5. 如果还提供粗糙度贴图.roughnessMap,则两个值相乘 .clearcoat 表示clear coat层的强度,范围从0.0到1.0m,当需要在表面加一层薄薄的半透明材质的时候,可以使用与clear coat相关的属性,默认为0.0 .clearcoatRoughness clear coat层的粗糙度,由0.0到1.0。 默认为0.0 .metalnessMap和.roughnessMap 金属度贴图.metalnessMap和粗糙度贴图.roughnessMap 金属度贴图.metalnessMap纹理的蓝色通道用于改变材料的金属度 粗糙度贴图.roughnessMap纹理的绿色通道用于改变材料的粗糙度 Clearcoat Clearcoat: Clearcoat可以在不需要重新创建一个透明的面的情况下实现类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。而且这个面说不定有一定的起伏与粗糙度等类似的效果 定义车身材质
// 车身材质
let bodyMaterial = new THREE.MeshPhysicalMaterial({
color: "#6e2121",
metalness: 1,
roughness: 0.5,
clearcoat: 1.0,
clearcoatRoughness: 0.03, //clear coat层的粗糙度,由0.0到1.0。 默认为0.0
})
创建车架、车座、轮胎及把手材质
用上面同样的方法,创建车架、车座、轮胎及把手材质,代码如下
// 车架
let frameMaterial = new THREE.MeshPhysicalMaterial({
color:"#c0c0c0",
metalness:1,
roughness:0.5,
clearcoat:1.0,
clearcoatRoughness:0.03
// 车座
let saddleMaterial = new THREE.MeshPhysicalMaterial({
color:"#5E2612",
metalness:0,
roughness:1
// clearcoat:1,
// clearcoatRoughness:1
// 轮胎
let tireMaterial = new THREE.MeshPhysicalMaterial({
color:"#000000",
metalness:0,
roughness:1,
clearcoat:0,
clearcoatRoughness:0.33
// 把手
let handleMaterial = new THREE.MeshPhysicalMaterial({
color:"#000000",
metalness:0,
roughness:1,
clearcoat:0,
clearcoatRoughness:0.33
})
定义initGUI() 方法
定义一个对象用于存储各个部分的颜色 首先我们在initGUI()方法中先定义一个对象,这个对象包含上面各个部分的颜色
initGUI() {
var obj = {
bodyColor: '#6e2121',// 车身颜色
frameColor:'#c0c0c0',// 车架颜色
saddleColor:'#5E2612',// 车座颜色
tireColor:'#000000' ,// 轮胎颜色
handleColor:'#000000' ,// 车把颜色
glassColor: '#aaaaaa',
}
实例化一个GUI
通过
const gui = new GUI()
来实例化一个GUI
添加车身颜色控制面板
利用gui的.addColor()方法将obj对象绑定到GUI中,并对其命名,然后其onChange()事件中监听用户点击的颜色值,并将该值赋值给上面定义的车身材质
gui.addColor(obj, "bodyColor").name('车身颜色').onChange((value) => {
bodyMaterial.color.set(value)
})
刷新浏览器,可以看到在右上角已经出现了GUI的控制面板,点击车身颜色,可以弹出颜色面板 添加车架、车座、轮胎及把手的控制面板 用同样的方法添加车架、车座、轮胎及把手的控制面板
遍历模型,修改模型各Mesh的颜色
通过上面的代码,我们已经将GUI添加到了屏幕上, 但是我们在弹出的颜色窗口中点击修改颜色时,三维场景中的摩托车对应的部位并没有修改颜色,这是因为我们还没有将上面定义的Mesh材质与模型中的Mesh关联。
.traverse递归遍历模型
Threejs为我们提供了一个递归遍历的方法.traverse,使用它可以遍历很方便的获取我们需要的Mesh,traverse提供了一个回调函数,我们在traverse的回调函数中通过判断对象的name属性来获取模型的各个部分。在我们之前写的 addGLTFModel()方法中使用traverse方法,通过if语句判断模型的名称,找到对应的模型名称后,将上面定义的各个材质赋值给模型对应部分的material属性,将bodyMaterial属性赋值给模型的车身
// 加载模型
addGLTFModel(modelName) {
return new Promise((resolve,reject) => {
const loader = new GLTFLoader().setPath('3dModels/')
loader.load(modelName,(gltf) =>{
const motorModel = gltf.scene
motorModel.traverse(obj => {
if(obj.name === "网格457") {
// 车身
obj.material = bodyMaterial
} else if (obj.name === "网格457_1") {
// 车灯
// obj.material = glassMaterial
} else if (obj.name === "网格457_2") {
// 座位
obj.material = saddleMaterial
} else if (obj.name === "网格457_4") {
// 车把
obj.material = handleMaterial
} else if (obj.name === "网格457_3" || obj.name === "网格457_5" || obj.name === "网格457_6") {
// 车架
obj.material = frameMaterial
} else if (obj.name === "网格457_7") {
// 轮胎
obj.material = tireMaterial
} else {
obj.castShadow = true;
this.scene.add(motorModel)
resolve(this.modelName + '模型添加成功')