three.js教程7-PBR材质与环境贴图CubeTextureLoader
1、PBR材质
PBR是基于物理的渲染(physically-based rendering)。模拟物体表面的反射算法。
Three.js提供了两个PBR材质相关的类MeshStandardMaterial
和MeshPhysicalMaterial
MeshPhysicalMaterial是MeshStandardMaterial扩展的子类,提供了更多功能属性。
PBR材质相比MeshLambertMaterial和MeshPhongMaterial可以提供更逼真的、更接近生活中的材质效果,当然也会占用更多的电脑硬件资源。
PBR相关理论介绍文章
半小时了解PBR:https://zhuanlan.zhihu.com/p/37639418
PBR知识体系整理:https://zhuanlan.zhihu.com/p/100596453
PBR核心知识体系总结与概览:https://zhuanlan.zhihu.com/p/53086060
2、MeshStandardMaterial材质实现金属效果
(1) 金属度metalness、粗糙度roughness
//金属度 //默认是0.5,范围是0到1之间。木材或石材用0,金属使用1。 mesh.material.metalness = 1.0; //表面粗糙度 //默认0.5,范围是0~1之间,0表示平滑的镜面反射,1表示完全漫反射, mesh.material.roughness = 0.5;
(2)环境贴图.envMap=CubeTextureLoader()立方体纹理加载器加载环境贴图
环境贴图,是一个模型周围的环境的图像,比如:室内模型的环境贴图是:房子四周墙壁环境,房子的上下左右前后分别拍摄一张照片,就是3D空间中6个角度方向的照片。
// 加载环境贴图 // 加载周围环境6个方向贴图 // 上下左右前后6张贴图构成一个立方体空间 // 'px.jpg', 'nx.jpg':x轴正方向、负方向贴图 p:正positive n:负negative // 'py.jpg', 'ny.jpg':y轴贴图 // 'pz.jpg', 'nz.jpg':z轴贴图 const textureCube = new THREE.CubeTextureLoader() .setPath('./环境贴图/环境贴图0/') .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); // CubeTexture表示立方体纹理对象,父类是纹理对象Texture new THREE.MeshStandardMaterial({ metalness: 1.0, roughness: 0.5, envMap: textureCube, //设置pbr材质环境贴图 })
(3)环境贴图强度envMapIntensity-环境贴图反射率
// envMapIntensity:控制环境贴图对mesh表面影响程度 //默认值1, 设置为0相当于没有环境贴图 obj.material.envMapIntensity = 1.0;
(4)场景环境属性.environment
加载gltf模型后,如果你希望环境贴图影响场景中scene所有Mesh,1、可以循环遍历模型设置envMap,2、也可以通过Scene的场景环境属性.environment
实现。
//方法1 loader.load("../工厂.glb", function (gltf) { // 递归遍历批量设置环境贴图 gltf.scene.traverse(function (obj) { if (obj.isMesh) { //判断是否是网格模型 obj.material.envMap = textureCube; //设置环境贴图 } }); }) //方法2: // 环境贴图纹理对象textureCube作为.environment属性值,影响所有模型 scene.environment = textureCube; //如果renderer.outputEncoding=THREE.sRGBEncoding;环境贴图需要保持一致 textureCube.encoding = THREE.sRGBEncoding;
3、MeshPhysicalMaterial材质-新增属性
(1)清漆层clearcoat和清漆层粗糙度.clearcoatRoughness
clearcoat:模拟物体表面一层透明图层,类似车漆的抛光打蜡,具有透明和反光特性,值越大反光效果越好。clearcoatRoughness,值越大反光效果越弱。
const material = new THREE.MeshPhysicalMaterial( { clearcoat: 1.0,//半透明涂层的厚度,默认是0,范围是0~1m clearcoatRoughness: 0.1,//半透明涂层表面的粗糙度,默认是0,范围是0~1 } );
(2) 玻璃的透光率(透射度).transmission
物理光学透明度.transmission
的值范围是从0.0到1.0。默认值为0.0。
const mesh = gltf.scene.getObjectByName('玻璃01') mesh.material = new THREE.MeshPhysicalMaterial({ transmission: 1.0, //玻璃材质透光率,transmission替代opacity })
(3) 折射率ior
非金属材料的折射率从1.0到2.333。默认值为1.5。
不同材质的折射率,你可以百度搜索。
new THREE.MeshPhysicalMaterial({ ior:1.5,//折射率 })
(4)反射率.reflectivity
、光泽.sheen
4、三维软件导出PBR材质属性
实际开发的时候PBR材质的属性,很多时候是可以在三维建模软件中设置的,然后通过gltf导出即可,这样就不用在threejs代码设置。
通常美术对三维场景渲染的了解也比大部分前端程序员多的多,只要美术在三维建模软件设置好并导出包含pbr材质属性的gltf即可。
(1)threejs解析gltf材质规则
threejs解析gltf模型材质的时候,一般默认使用标准网格材质MeshStandardMaterial
,如果gltf有的材质具有.clearcoat
、.transmission
等属性,标准网格材质MeshStandardMaterial
无法表达的时候,会用物理网格材质MeshPhysicalMaterial
来解析gltf材质。
(2)设置环境贴图
这时候清漆、清漆粗糙度、透光率(透射度)等属性Bledner都已经设置好了,threejs可以自动解析渲染,不用在代码中麻烦设置了,只要配上环境贴图即可。
// 加载环境贴图 const textureCube = new THREE.CubeTextureLoader() .setPath('../../环境贴图/环境贴图1/') .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); textureCube.encoding = THREE.sRGBEncoding; //设置纹理贴图编码方式和WebGL渲染器一致 // 加载gltf模型,然后给指定模型设置环境贴图 loader.load("../../轿车.glb", function (gltf) { model.add(gltf.scene); const mesh = gltf.scene.getObjectByName('玻璃01'); mesh.material.envMap=textureCube; mesh.material.envMapIntensity=1.0; })
示例1:金属效果
const model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景 // 加载环境贴图 // 加载周围环境6个方向贴图 // 上下左右前后6张贴图构成一个立方体空间 // 'px.jpg', 'nx.jpg':x轴正方向、负方向贴图 p:正positive n:负negative // 'py.jpg', 'ny.jpg':y轴贴图 // 'pz.jpg', 'nz.jpg':z轴贴图 // CubeTexture表示立方体纹理对象,父类是纹理对象Texture const textureCube = new THREE.CubeTextureLoader() .setPath('../../环境贴图/环境贴图1/') .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); const loader = new GLTFLoader(); //创建一个GLTF加载器 loader.load("../../金属.glb", function (gltf) { // 递归遍历所有模型节点批量修改材质 gltf.scene.traverse(function (obj) { if (obj.isMesh) { //判断是否是网格模型 // console.log('obj.material',obj.material); // 重新设置材质的金属度和粗糙度属性 obj.material.metalness = 1.0; //金属度 obj.material.roughness = 0.3; //表面粗糙度 obj.material.envMap = textureCube; //设置环境贴图 // envMapIntensity:控制环境贴图对mesh表面影响程度 obj.material.envMapIntensity = 1.0;//默认值1, 设置为0.0相当于没有环境贴图 } }); model.add(gltf.scene); })
示例2:车外壳油漆反光效果-清漆层属性clearcoat
const model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景 // 加载环境贴图 const textureCube = new THREE.CubeTextureLoader() .setPath('../../环境贴图/环境贴图1/') .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); textureCube.encoding = THREE.sRGBEncoding; //设置纹理贴图编码方式和WebGL渲染器一致 const loader = new GLTFLoader(); //创建一个GLTF加载器 loader.load("../../轿车.glb", function (gltf) { model.add(gltf.scene); // 车外壳包含多个Mesh,获取其中一个 const mesh = gltf.scene.getObjectByName('外壳01'); mesh.material = new THREE.MeshPhysicalMaterial({ color: mesh.material.color, //默认颜色 metalness: 0.9,//车外壳金属度 roughness: 0.5,//车外壳粗糙度 clearcoat: 1, //清漆层 clearcoatRoughness: 0.01, //清漆层粗糙度 envMap: textureCube, //环境贴图 envMapIntensity: 2.5, //环境贴图对Mesh表面影响程度 }) })
示例3:车玻璃效果-透光率transmission和折射率ior
const model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景 // 加载环境贴图 const textureCube = new THREE.CubeTextureLoader() .setPath('../../环境贴图/环境贴图1/') .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); textureCube.encoding = THREE.sRGBEncoding; //设置纹理贴图编码方式和WebGL渲染器一致 // 加载gltf模型 const loader = new GLTFLoader(); //创建一个GLTF加载器 loader.load("../../轿车.glb", function (gltf) { model.add(gltf.scene); const mesh = gltf.scene.getObjectByName('玻璃01') mesh.material = new THREE.MeshPhysicalMaterial({ metalness: 0.0,//玻璃非金属 roughness: 0.0,//玻璃表面光滑 envMap:textureCube,//环境贴图 envMapIntensity: 1.0, //环境贴图对Mesh表面影响程度 transmission: 1.0, //玻璃材质透光率,transmission替代opacity ior:1.5,//折射率 }) })
文章中部分素材选取自Threejs中文网:http://www.webgl3d.cn/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)