threejs – src – material和shader是如何对应的?

threejs – src – material和shader是如何对应的?

在上一篇文章中threejs – src – WebGLProgram是如何组建Shader的? – grassofsky – 博客园 (cnblogs.com),我们介绍了WebGLProgram中如何组建Shader,如何获取对应的unifrom的,以及简单的介绍了下WebGLProgram关联的uniform值是如何设置的。

文本重点针对的问题是:

  • 不同的材质如何对应到不同的Shader?
  • 材质中的属性和Shader中的属性之间是如何进行关联的?

不同材质如何对应不同的Shader?

在上一篇文章中,我们知道ShaderLib中提供了内置的Shader类型,示例如下(通过对象的形式存储):

// ShaderLib.js
const ShaderLib = {
    basic: {...},
    lambert: {...},
    phong: {...},
    ...
}

那么必然在代码的某处,我们会使用上面的key,来关联具体的shader,在代码中检索命名比较特殊的key,此处选择为distanceRGBA,搜索结果如下:

很快就能够发现,ShaderLib的key被重新映射了,具体如下:

const shaderIDs = {
    MeshDepthMaterial: 'depth',
    MeshDistanceMaterial: 'distanceRGBA',
    ...
};

此处重新映射后,key的值,就是具体的Material对应的类名,这样两者的关系就建立起来了。使用的时候直接通过Material的type属性(该属性对应的是Material具体的类名),去获取具体的shader字符串。具体代码见WebGLPrograms的getParameters函数,

WebGLRenderer渲染流程

在介绍属性和shader uniform之间的关联之前,先过一下WebGLRenderer的渲染流程。渲染流程的入口函数为:renderer.render(scene, camera);这个时候已经构建好场景以及相机,示意图可能是这样的:

那么渲染器是怎么执行渲染的呢?大致的流程如下图所示(图中绿线为函数开始执行的地方,红线表示函数返回的地方):

此处Material和uniform相关的逻辑位于setProgram中。

材质中的属性和Shader中的属性之间是如何进行关联的?

正如上一节所述,相关的主要逻辑位于WebGLRenderer.setProgram函数中,让我们来看下这个函数重点干了啥?为了简化流程,我们先假设,_clippingEnabled = false; object.isSkinnedMesh = false;materialProperties.__version还没有赋值,不考虑morph,不考虑阴影,并不是spriteMaterial,不考虑texture,那么基本流程如下:

图中红色的框getProgram函数,实现了material和shader的关联,绿色的框实现了参数往实际shader中的传递。关于WebGLProgram可以参见:threejs – src – WebGLProgram是如何组建Shader的? – grassofsky – 博客园 (cnblogs.com)

待办项 TODO List

  • 渲染状态是怎么管理的?
  • renderlist是怎么管理的?
  • projectObject是干啥用的?