THREE中透明物体绘制原理解析
1.WebGL中透明物体绘制原理
1.1开启深度测试和Blend功能
开启深度测试
gl.enable(gl.DEPTH_TEST)
开启混合
gl.enable(gl.BLEND)
指定混合函数
gl.blendFunc(gl.SRC_ALPHA,gl.ONE.MINUS_SRC_ALPHA)
1.2首先绘制所有不透明的物体队列
Three中是在render函数中分类函数遍历将非透明物体和透明服务装入的currentRenderList中
1.3关闭深度写入功能
准备绘制透明物体前的准备工作,先gl.depthMask(false)
,对应THREE中的材质中的DepthWrite
参数为false
,主要为了用于透明物体绘制,使得锁定隐藏面消除的深度缓冲区的写入操作,使之只读。
1.4绘制所有半透明的物体
绘制之前应当将透明物体根据深度排序好,然后从后往前绘制,绘制过程中利用之前不透明对象绘制后的深度缓冲区进行深度测试,通过深度测试才会绘制不透明三角面片,具体就要用到Blending相关算法
1.5释放深度缓冲区,使之可读可写
gl.depthMask(true)
,绘制完透明物体就要开启深度写入功能了,用于下一帧的非透明物体数组的绘制
2.THREE中透明物体绘制相关流程解析
2.1 render函数中的projectObject
用于遍历对象,深度排序,
2.2 透明和不透明分组
此处的currentRenderList是WebGLRenderLists.js的WebGLRenderList对象,sort函数传入透明对象和非透明对象的排序函数规则
此处非透明函数用默认函数painterSortStable,透明函数排序用reversePainterSortStable
具体非透明函数实现如下图所示
从非透明排序函数可以看出,排序优先级groupOrder>renderOrder>program.id>material.id>z深度
透明函数排序
从透明排序函数可以看出,排序优先级groupOrder>renderOrder>z深度
综上,可以知道排序规则,因为非透明和透明是两个渲染队列,因此Order互不影响,只是本身队列可以提高优先级,order默认都是0
2.3 开始渲染
可以看到此处先渲染不透明的,再渲染透明的
2.3.1 renderObjects至renderBufferDirect
2.3.2 setprogram
var program = setProgram(camera, scene, material, object);此处进行uniform等值的赋值等操作
最终将uniforms组装进materialProperties.uniformsList = uniformsList;
2.3.2 state.setMaterial(material)
该类在render函数中使用setMaterial方法,读入当前待渲染对象的material,读取材质中的有关深度状态和混合blend等信息。
该类中的DepthBuffer用于管理深度缓冲状态
setTest(true|false)
用于深度测试状态管理
setMask(true|false)
用于深度写的状态管理
setFunc(depthFunc枚举)
用于深度缓冲规则的确认,一般默认即可
此处开始进入正题,研究threejs对透明物体的渲染状态处理
2.3.3 renderer.render(drawStart, drawCount);
进行最终的绘制
3 透明材质正确打开方式
3.1 transparent
在场景中,绘制transparent必须要打开,否则会将该对象默认分类到非透明渲染队列
3.2depthWirte
在材质中的depthWrite
用于深度写的状态控制,depthTest
用于深度测试状态控制,默认打开即可,通常情况下绘制透明物体在配置透明属性外还需要关闭depthWrite
(2020-3-26)近期较忙,暂记录待后续补充…