Three.js-WebGLRenderer

Three.js是通过WebGLRenderer渲染场景的,因此只要把WebGLRenderer的每一个概念和属性搞清楚,做出Demo查看其影响范围,就能把如何调试渲染效果给掌握了。

建议先了解下WebGL的理论基础知识,不然里面有些名词概念会造成理解障碍。

这里我们就对其中影响渲染效果的关键属性进行分析。

构造参数

属性

clippingPlanes

场景中和Plane点乘为负数的点,会被裁减掉,不进行渲染。

我们之前在目标策略图中的模型裁剪,其原理应该就是使用的这个。

outputEncoding

渲染器的输出编码格式。这些都是针对Texture的设置。

注意如果是动态修改该属性,要记得修改后,设置material的needsUpdate为true,否则不会生效。

属性值 描述 适用场景
THREE.LinearEncoding 默认的编码格式 科技感场景,比如汽车展厅、科幻风格等
THREE.sRGBEncoding 更符合人眼感知的编码格式
THREE.BasicDepthPacking
THREE.RGBADepthPacking

physicallyCorrectLights

toneMapping & toneMappingExposure

这是个重头戏,主要是为了在LDR(Low Dynamic Range)设备(普通计算机显示器或者移动设备屏幕等低动态范围介质上),模拟、逼近高动态范围(HDR)效果。

属性值 描述 适用场景
THREE.NoToneMapping 默认
THREE.LinearToneMapping
THREE.ReinhardToneMapping
THREE.CineonToneMapping
THREE.ACESFilmicToneMapping 效果最好
THREE.CustomToneMapping 自定义,需修改GLSL

shadowMap

type

这是对shadowMap的引用,如果不开启,就没有阴影效果。这个默认是false。

不过即使renderer中不开启,后面其他地方启用了阴影,也是会生效的。
(TODO)待验证下。

soft shadow:柔和阴影,即模拟阴影渐变且在阴影周边制造虚化的效果。

属性值 描述 适用场景
THREE.BasicShadowMap 未过滤的阴影映射,快,但是质量低 低端机型
THREE.PCFShadowMap 默认,采用Percentage-Closer Filtering算法
THREE.PCFSoftShadowMap 低分辨率阴影贴图
THREE.VSMShadowMap 使用Variance Shadow Map算法,使用该算法,所有阴影接收者都会投射阴影

sortObjects

是否开启透明物体的渲染排序,默认是true

一般我们可以手动设置物体renderOrder属性来确定其渲染顺序。

方法

clear ( color : Boolean, depth : Boolean, stencil : Boolean )

知识点来了:三个缓存

  • 颜色缓存
  • 深度缓存
  • 模板缓存

有3个单独的方法一一对应:

1
2
3
4
5
6
7
8
.clearColor ( ) : undefined
Clear the color buffer. Equivalent to calling .clear( true, false, false ).

.clearDepth ( ) : undefined
Clear the depth buffer. Equivalent to calling .clear( false, true, false ).

.clearStencil ( ) : undefined
Clear the stencil buffers. Equivalent to calling .clear( false, false, true ).

dispose()

其他

渲染顺序与renderOrder

https://segmentfault.com/a/1190000041221932

Three.js默认的渲染顺序:

  1. 首先,把场景中的物体根据是否透明划分为两个数组;
  2. 对于不透明物体所在的数组,按照由近及远的顺序排序;
  3. 对于透明物体所在的数组,按照由远及近的顺序排序;
  4. 绘制不透明物体所在的数组;
  5. 绘制透明物体所在的数组。

不透明的物体

像素点的深度缓冲

直接舍弃,相当于是个Boolean类型

在渲染不透明物体的时候,最终的实现效果和物体绘制的前后顺序没有关系

透明的物体

混合(Blend)

透明物体的最终渲染结果和物体的绘制顺序相关。

当透明物体按照由远及近的顺序绘制时,结果会在更大程度上符合我们的预期;

当透明物体按照由近及远的顺序绘制时,结果基本上不会符合我们的预期,除非你是有意为之。

不透明物体和透明物体一起渲染

控制深度测试

前面我们有说到深度测试,深度测试的三个步骤都是可以控制的:

  1. 是否进行深度测试;
  2. 深度测试函数的行为;
  3. 是否更新深度缓冲区。

这三个步骤分别是通过Material的下面三个属性控制的:

  1. depthTest:是否进行深度测试;
  2. depthFunc:深度测试函数的行为;
  3. depthWrite:是否更新深度缓冲区。

此外,当你需要开启深度测试的时候,需要在初始化WebGLRenderer的时候开启depth参数,这个参数会创建一个深度缓冲区。这个参数的默认值是true,也就是一般情况下你不用关注这个属性。当然,如果你的需求明确不需要深度测试,并且性能要求比较高的话,你可以手动关闭这个值,减少一定的存储成本。

控制绘制顺序

前面我们有提到,THREE.js绘制不透明物体和透明物体分别是按照由近及远和由远及近的顺序绘制的,那么这个排序是THREE.js给我们实现的吗?还是需要我们自己控制绘制顺序?

THREE.js默认是开启排序的,这个是通过WebGLRenderer的sortObjects属性实现的。如果不开启自动排序,绘制顺序就是物体的添加顺序(注意,此时透明物体和非透明物体仍然是分开渲染的)。

不透明物体和透明物体的默认排序顺序可以参考源码的painterSortStable和reversePainterSortStable方法。

那么,我们如何干预上述排序过程呢?主要有如下两种方式:

  1. 上述两个方法,我们可以注意到其中有renderOrder属性,这个属性就是我们需要的,具体说明可以参见renderOrder文档
  2. 通过setOpaqueSortsetTransparentSort完全自定义排序逻辑。

自定义混合(blend)函数

前面我们讲透明物体渲染的时候有提到透明物体的默认混合函数是NormalBlending。这个混合函数的行为也是可选的,具体可支持的行为可以参考Material.blending

总结

本文主要讲述了THREE.js中的不透明物体和透明物体的渲染顺序,主要涉及THREE.js的以下内容:

  1. Material

    1. depthWrite(default is true)
    2. depthTest(default is true)
    3. depthFunc(default is LessEqualDepth)
    4. blending及blending相关的一系列属性
  2. Object3D

    1. renderOrder(default is 0)
  3. WebGLRenderer

    1. depth
    2. sortObjects(default is true)
    3. setOpaqueSort
    4. setTransparentSort

上述观点是基于目前对THREE.js的研究结果,可能会有认知错误。如有,欢迎留言评论。