提升Three.js渲染效果的一些方法(一)

在Three.js的3D场景渲染中,若不经过一番特殊处理,通常所呈现出的效果也难以尽如人意,就像下图这样: 图1

图1是按照常规操作加载了模型、添加了光照后的样子,可以看出汽车模型所表现出的一股塑料感扑面而来。

图2是做了效果优化后的样子: 图2

可以明显看到,图2的车身更具光泽、车窗车灯也有了逼真的玻璃材质、汽车的倒影也给场景增添了更多质感。

接下来我们就来看看如何一步步化腐朽为神奇提升图1的渲染效果从而呈现出一个具有真实感的3D场景。

添加HDR贴图

HDR(High Dynamic Range)即高动态范围贴图,借助HDR我们可以使用超出普通范围的颜色值,通常我们用HDR来实现场景照明和模拟反射折射、从而实现更具真实感的渲染效果。在Three.js中使用RGBELoader来加载HDR贴图:

js 复制代码
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
......
// 添加HDR贴图
scene.environment = new RGBELoader().load( 'textures/equirectangular/venice_sunset_1k.hdr' );				
scene.environment.mapping = THREE.EquirectangularReflectionMapping;	

设置颜色空间

Three.js在导入材质时会默认使用THREE.LinearEncoding颜色空间的编码方式,而在GLTF中始终使用sRGB颜色空间,为了保证三维模型在Three.js中和三维建模软件中呈现出尽可能一致的渲染效果,则需按如下方式配置 WebGLRenderer:

js 复制代码
renderer.outputEncoding = THREE.sRGBEncoding;

设置物理材质

为了使汽车看起来更具有真实感,还要为其相应的部位添加物理材质。物理材质(PBR)模拟了真实世界中物体与光的交互,从而可以呈现出更多的真实感。在Three.js中可以使用THREE.MeshPhysicalMaterial来设置物理材质,通常我们需要关注以下的参数:

color:基础色。材质的基础颜色。

metalness:金属度。取值范围为0.0到1.0,取值越大外观越接近金属材料。

roughness:粗糙度。取值范围为0.0到1.0,取值越小镜面反射越明显,取值越大漫反射越明显。

clearcoat:透明涂层,一种表面像涂了一层透明油漆的材质。取值范围为0.0到1.0,取值越大透明涂层的效果越明显。

clearcoatRoughness:透明涂层的粗糙度。取值范围为0.0到1.0,取值越大透明涂层的粗糙程度越明显。

transmission:透光率。用来模拟玻璃等透明材料。取值范围为0.0到1.0,取值越大透光性越好。

可以在三维建模软件Blender中查看汽车模型各个关键部位的命名,然后针对其设置相应的物理材质(PBR)参数:

js 复制代码
const bodyMaterial = new THREE.MeshPhysicalMaterial( {
    color: 0x0125CD, 
    metalness: 1.0, 
    roughness: 0.5, 
    clearcoat: 1.0, 
    clearcoatRoughness: 0.03
} );
const detailsMaterial = new THREE.MeshPhysicalMaterial( {
    color: 0xffffff, 
    metalness: 1.0, 
    roughness: 0.5
} );
const glassMaterial = new THREE.MeshPhysicalMaterial( {
    color: 0xffffff, 
    metalness: 0.25, 
    roughness: 0, 
    ransmission: 1.0
} );
loader.load( 'models/gltf/car-blue.glb', function ( gltf ) {
    const carModel = gltf.scene.children[ 0 ];
    carModel.getObjectByName( 'body' ).material = bodyMaterial;
    carModel.getObjectByName( 'rim_fl' ).material = detailsMaterial;
    carModel.getObjectByName( 'rim_fr' ).material = detailsMaterial;
    carModel.getObjectByName( 'rim_rr' ).material = detailsMaterial;
    carModel.getObjectByName( 'rim_rl' ).material = detailsMaterial;
    carModel.getObjectByName( 'trim' ).material = detailsMaterial;
    carModel.getObjectByName( 'glass' ).material = glassMaterial;
    carModel.scale.set(0.05, 0.05, 0.05)		
    scene.add( carModel );
} );

添加反射效果

反射效果是通过在Three.js的后期效果合成中添加相应的通道来实现的,ReflectorForSSRPass、SSRPass通道搭配起来能实现更真实、更可控的反射效果,包括镜像反射和屏幕空间反射。

js 复制代码
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { ReflectorForSSRPass } from 'three/addons/objects/ReflectorForSSRPass.js';
import { SSRPass } from 'three/addons/postprocessing/SSRPass.js';
......
let ReflectorGeometry = new THREE.PlaneGeometry( 1, 1 );
groundReflector = new ReflectorForSSRPass( ReflectorGeometry, {
    clipBias: 0.0003,
    textureWidth: window.innerWidth,
    textureHeight: window.innerHeight,
    color: 0x888888,
    useDepthTexture: true,
} );
groundReflector.material.depthWrite = false;
groundReflector.rotation.x = - Math.PI / 2;
groundReflector.visible = false;
scene.add( groundReflector );

composer = new EffectComposer( renderer );

let ssrPass = new SSRPass( {
    renderer,
    scene,
    camera,
    width: innerWidth,
    height: innerHeight,
    groundReflector: groundReflector,
    selects: []
} );

composer.addPass( ssrPass );
ssrPass.thickness = 0.018;
ssrPass.infiniteThick = false;
ssrPass.maxDistance = .1;
groundReflector.maxDistance = 0.036
ssrPass.opacity = 1;
groundReflector.opacity = 0.317;

在反射通道的设置中有两个参数可以着重留意一下:

reflector.maxDistance:用来设置镜像反射的距离。

reflector.opacity:用来设置镜像反射的透明度。

js 复制代码
groundReflector.maxDistance = 0.036;
groundReflector.opacity = 0.317;

接下来还需要使用Three.js的GammaCorrectionShader来解决由于颜色空间问题而导致的画面颜色异常:

js 复制代码
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';
......
composer.addPass( new ShaderPass( GammaCorrectionShader ) );

最后就大功告成了!

总结

本文我们通过添加HDR贴图、设置颜色空间、设置物理材质、添加反射等方式一步步地提升渲染效果从而实现了一个真实感3D场景的渲染。当然提升渲染效果的方式也并非仅仅只有这些,像烘焙贴图、软阴影、环境光遮蔽、抗锯齿、自定义着色器等等也是我们在具体的项目中会用到的方案,后面我们结合相应的案例再详细地聊一聊这些话题。

本文使用的Three.js版本为r150。

本文完整的工程文件:提升Three.js渲染效果的一些方法(一)

相关推荐
格瑞@_@3 天前
11.Three.js使用indexeddb前端缓存模型优化前端加载效率
前端·javascript·缓存·three.js·indexeddb缓存
谢小飞3 天前
我做了三把椅子原来纹理这样加载切换
前端·three.js
小白菜学前端3 天前
ThreeJS创建一个3D物体的基本流程
3d·three.js
茶老翁4 天前
1-初识Three.js
前端·three.js
莫石6 天前
搓绳子(直)
前端·数学·three.js
小白菜学前端6 天前
3d 添加辅助坐标器和轨道控制器
3d·three.js
孙_华鹏8 天前
threejs——实战中材质的应用
前端·three.js·数据可视化
天涯学馆11 天前
Three.js灯光阴影与动画交互
前端·unity3d·three.js
格瑞@_@15 天前
6.Three.js贴图与uv映射(uv坐标)理解和实践
javascript·three.js·贴图·uv
入秋丶24 天前
threejs - 包围盒和包围球
three.js