THREE.WebGLRenderer对象的参数设置非常影响渲染效果
要想获得比较好的渲染效果,对THREE.WebGLRenderer可进行以下参数设置。
- var renderer;
- renderer = new THREE.WebGLRenderer({
- antialias:true
- });
- renderer.physicallyCorrectLights = true;
- renderer.setPixelRatio( window.devicePixelRatio * 2);
- renderer.setSize(window.innerWidth,window.innerHeight);
- renderer.gammaOutput = true;
- renderer.shadowMap.enabled = true;
- renderer.shadowMap.type = THREE.PCFSoftShadowMap;
- renderer.toneMapping = THREE.ACESFilmicToneMapping;
- renderer.toneMappingExposure = 1.0;
- renderer.outputEncoding = THREE.sRGBEncoding;
- document.body.appendChild(renderer.domElement);
上述设置中,
1. 抗锯齿
- renderer = new THREE.WebGLRenderer({
- antialias:true,
- //alpha:true
- });
将antialias设置为true表示开启抗锯齿。
2. 物理灯光
renderer.physicallyCorrectLights = true;
表示将启用正确的物理灯光。
3. 像素采样率
renderer.setPixelRatio( window.devicePixelRatio * 2);
表示使用2倍设备像素点采样,这有利于消除锯齿获得更加高质量的效果。
4. 阴影贴图
- renderer.shadowMap.enabled = true;
- renderer.shadowMap.type = THREE.PCFSoftShadowMap;
上述设置表示启用阴影贴图,并将阴影贴图类型设置为THREE.PCFSoftShadowMap,其中不同阴影贴图类型的设置如下:
5. 色彩映射
- renderer.toneMapping = THREE.ACESFilmicToneMapping;
- renderer.toneMappingExposure = 1.0;
设置这个属性主要是为了在普通计算机显示器或者移动设备屏幕等低动态范围介质上,模拟、逼近高动态范围(HDR)效果。
这个属性如果要生效就是需要将hdr贴图作为场景的环境贴图,获取IBL的光照效果。使用hdr贴图作为场景的环境贴图也将大幅度提升场景或者模型的渲染效果。
其中toneMapping算法可选择:
这里我们使用的是效果最好的ACES算法,当然你也可以自定义自己的tonemapping算法,如何自定义可参考官方示例。
而toneMappingExposure表示曝光级别,值越大曝光程度越高,场景中的光线越充足,模型就越亮。
6. 渲染器输出编码
renderer.outputEncoding = THREE.sRGBEncoding;
设置渲染器的输出编码,默认的输出编码为THREE.LinearEncoding,我们这里设置为THREE.sRGBEncoding。
three.js将贴图的编码都默认设置为THREE.LinearEncoding,导致图片色彩失真(色彩不像正常那么鲜艳,会灰蒙蒙的),所以务必将场景中的所有贴图的编码都调整为THREE.sRGBEncoding。
1. 贴图修改encoding
- const textureLoader = new THREE.TextureLoader();
- textureLoader.load( "./model_D.png", function(texture){
- texture.encoding = THREE.sRGBEncoding;
- });
2. 环境贴图修改encoding
- const hdrUrl = './res/hdr/ballroom_1k.hdr'
- new THREE.RGBELoader().load(hdrUrl, texture => {
- const gen = new THREE.PMREMGenerator(renderer)
- envMap = gen.fromEquirectangular(texture).texture;
- envMap.encoding = THREE.sRGBEncoding;
- scene.environment = envMap;
- scene.background = envMap;
-
- texture.dispose();
- gen.dispose();
- })
环境光会均匀的照亮场景中的所有物体,环境光不能产生阴影,因为环境光没有方向。
- const light = new THREE.AmbientLight( 0x404040 ); // soft white light
- scene.add( light );
半球光同样也是照亮场景中的所有物体,并且光照颜色会从天空光照颜色慢慢的渐变到地面光照颜色。
- const light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
- scene.add( light );
平行光是沿着特定方向发射的光。这种光的表现像是无限远,发出的平行光线,常常用来模拟太阳光。
平行光可以产生阴影,所以我们可以对平行光的阴影进行更多的设置。
- const directional_light = new THREE.DirectionalLight( 0xffffff, 1 );
- directional_light.position.set( 0, 1, 0 );
- directional_light.castShadow = true;
- scene.add( directional_light );
-
- directional_light.shadow.mapSize.width = 512 * 2;
- directional_light.shadow.mapSize.height = 512 * 2;
- directional_light.shadow.bias = 0.05;
- directional_light.shadow.normalBias = 0.05;
- directional_light.shadow.camera.near = 0.5;
- directional_light.shadow.camera.far = 500;
点光源为为一个点向各个方向发射的光源,可以理解为一个灯泡发出的光。
点光源同样也可以产生阴影,所以我们也可以对点光源的阴影进行更多设置。
- const point_light = new THREE.PointLight( 0xffffff, 1, 100 );
- point_light.position.set( 0, 10, 4 );
- point_light.castShadow = true;
- scene.add( point_light );
-
- point_light.shadow.mapSize.width = 512 * 2;
- point_light.shadow.mapSize.height = 512 * 2;
- point_light.shadow.bias = 0.05;
- point_light.shadow.normalBias = 0.05;
- point_light.shadow.camera.near = 0.5;
- point_light.shadow.camera.far = 500;
聚光灯光线从一个点沿一个方向射出,随着光线照射的变远,光线圆锥体的尺寸也逐渐增大。
聚光灯同样也可以产生阴影,所以我们也可以对点光源的阴影进行更多设置。
- const spot_light = new THREE.SpotLight( 0xffffff );
- spot_light.position.set( 100, 1000, 100 );
- spot_light.castShadow = true;
- scene.add( spot_light );
-
- spot_light.shadow.mapSize.width = 512 * 2;
- spot_light.shadow.mapSize.height = 512 * 2;
- spot_light.shadow.camera.near = 500;
- spot_light.shadow.camera.far = 4000;
- spot_light.shadow.camera.fov = 30;
区域光不支持阴影,因此没有更多的阴影设置。
- const width = 10;
- const height = 10;
- const intensity = 1;
- const rect_light = new THREE.RectAreaLight( 0xffffff, intensity, width, height );
- rect_light.position.set( 5, 5, 0 );
- rect_light.lookAt( 0, 0, 0 );
- scene.add( rect_light )
基于图像的光照(Image based lighting, IBL)通过一张环境贴图(Environment Map)来保存物体周围的环境信息,并通过一系列处理模拟真实环境中的光照效果。IBL与固定光源相比能够提供更加真实的光照效果,所以如果你用固定光源得到的效果很差,可以使用一张好的hdr作为场景的环境贴图,相信渲染效果会更加真实。
这里我们一般使用hdr作为我们的环境贴图,找好符合场景渲染要求的hdr环境贴图,然后设置场景的toneMapping,
- renderer.toneMapping = THREE.ACESFilmicToneMapping;
- renderer.toneMappingExposure = 1.0;
然后加载hdr环境贴图,如下:
- const hdrUrl = './res/hdr/ballroom_1k.hdr'
- new THREE.RGBELoader().load(hdrUrl, texture => {
- const gen = new THREE.PMREMGenerator(renderer)
- envMap = gen.fromEquirectangular(texture).texture;
- envMap.encoding = THREE.sRGBEncoding;
- envMap.material = THREE.EquirectangularReflectionMapping;
- scene.environment = envMap;
- scene.background = envMap;
-
- texture.dispose();
- gen.dispose();
- })
然后修改场景中所有的mesh的材质的环境贴图
- scene.traverse(child => {
- if (child instanceof THREE.Mesh) {
- child.material.envMap = envMap;
- child.material.envMapIntensity = envMapIntensity;
- child.material.needsUpdate = true;
- child.castShadow = true;
- child.receiveShadow = true;
- }
- })
在加载模型时也需要对模型进行一些设置才能有好的效果,如何设置可参考以下代码
- new THREE.GLTFLoader().load('./example.glb', result => {
- model = result.scene || result.scenes[0];
-
- model.traverse(child => {
- if ( child.isMesh ) {
- child.castShadow = true;
- child.receiveShadow = true;
-
- if(child.material.map)
- {
- child.material.map.encoding = THREE.sRGBEncoding;
- child.material.map.anisotropy = 1;
- }
-
- if (child.material.emissiveMap)
- {
- child.material.emissiveMap.encoding = THREE.sRGBEncoding;
- }
-
- if (child.material.map || child.material.emissiveMap)
- {
- child.material.needsUpdate = true;
- }
-
- if(envMap)
- {
- child.material.envMap = envMap;
- child.material.envMapIntensity = 1;
- }
-
- }
- });
在加载模型完成之后,需要遍历模型的所有网格,并将所有网格材质的贴图的encoding修改为THREE.sRGBEncoding,然后设置所有网格材质贴图的环境贴图以及强度。
建议使用glb格式的模型