学完 PBR 材质之后,我们就能做出车窗玻璃和车身的质感了,那这节就来实现一个汽车选配的效果。

首先分析下思路:
加载汽车模型后,遍历找到车身和车窗的网格模型,调节材质为 MeshPhysicalMaterial 物理网格材质,设置环境贴图 envMap,并且调节车窗的透光率、车身的清漆度等,就可以实现一个比较逼真的质感。
接下来就开始写:
npx create-vite car-config

进入项目,安装依赖:
npm install
npm install --save three
npm install --save-dev @types/three
改下 src/main.js
import './style.css';
import * as THREE from 'three';
import {
OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import mesh from './mesh.js';
const scene = new THREE.Scene();
scene.add(mesh);
const directionLight = new THREE.DirectionalLight(0xffffff, 10);
directionLight.position.set(100, 100, 100);
scene.add(directionLight);
const ambientLight = new THREE.AmbientLight();
scene.add(ambientLight);
const helper = new THREE.AxesHelper(100);
scene.add(helper);
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 10000);
camera.position.set(100, 100, 100);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height)
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
document.body.append(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
window.onresize = function () {
const width = window.innerWidth;
const height = window.innerHeight;
renderer.setSize(width,height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
};
创建 Scene、Light、Camera、Renderer。
改下 style.css
body {
margin: 0;
}
写下 mesh.js
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
const mesh = new THREE.Group();
loader.load("./car.glb", function (gltf) {
console.log(gltf);
mesh.add(gltf.scene);
gltf.scene.traverse((obj) => {
if(obj.isMesh) {
console.log(obj.name, obj);
}
});
});
export default mesh;
下载这个 glb 文件到 public 目录下:


用 GLTFLoader 加载车的模型。
先跑下:
npm run dev


车模型太小了,调大一点:

gltf.scene.scale.set(40, 40, 40);

打开 devtools 看下,它有非常多的汽车部件的 mesh:

找到车窗、车身这俩 mesh,看下材质:



都是物理网格材质 MeshPhysicalMaterial,那我们就可以直接改了。
把上节的天空盒图片下载下来,放到 public 目录下:

然后加载纹理作为环境贴图 envMap:

const textureCube = new THREE.CubeTextureLoader()
.setPath('./forest/')
.load(['px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png']);
if(obj.material.isMeshPhysicalMaterial) {
obj.material.envMap = textureCube;
obj.material.envMapIntensity = 2;
}
不只是车身和车窗要设置环境贴图,所有的物理网格材质都要设置下。
之前车是这样:

加上环境贴图后是这样:

之后调节下车身的材质:

if(obj.name ==='车身') {
obj.material.metalness = 0.9;
obj.material.roughness = 0.2;
obj.material.clearcoat = 1;
obj.material.clearcoatRoughness = 0;
}
设置金属度 metalness 为 0.9,因为车身一般是金属的。
粗糙度 roughness 设置 0.2,比较光滑的感觉。
看下效果:

现在车身就比较真实了。
然后再调一下车窗玻璃的材质:

if(obj.name === '车窗') {
obj.material.color.set('white');
obj.material.transmission= 1;
obj.material.ior = 1.3;
}
设置完全透光、调节下折射率。

现在就能看到车内部了。
之前光线强度太强了,改成 1:

然后我们加上 GUI 来调节这些参数:



const gui = new GUI();
const body = gui.addFolder('车身');
const win = gui.addFolder('车窗');
body.addColor(obj.material, 'color');
body.add(obj.material, 'metalness', 0, 1);
body.add(obj.material, 'roughness', 0, 1);
body.add(obj.material, 'clearcoat', 0, 1);
body.add(obj.material, 'clearcoatRoughness', 0, 1);
win.addColor(obj.material, 'color');
win.add(obj.material, 'transmission', 0, 1);
win.add(obj.material, 'ior', 1, 2.3);
win.add(obj.material, 'metalness', 0, 1);
win.add(obj.material, 'roughness', 0, 1);


案例代码上传了小册仓库。
总结
这节我们练习了下 PBR 材质。
加载了车的模型,然后遍历找到车窗、车身的 mesh,修改 PBR 材质的金属度 metalness、粗糙度 roughness、清漆层 clearcoat、透光率 transmission、折射率 ior 等,就可以实现真实的车窗、车身的效果。
然后加上了 GUI 来可视化的调试,大家自己调一下看看效果,就能更好的理解 PBR 材质了。