前言: 最近做视频做到一半,突然发现要做还是得先了解下,免得妄自猜测随口一说误人子弟。大多数人会搜索到drawCommand大抵的需求都是与着色器之间(或者说webgl)产生数据交互。特有此文,希望可以帮助到你们。
drawCommand是什么?
首先drawCommand是什么?源码中的注释很简单,这就是一个绘制渲染的命令,在cesium里,每一帧都有大量的命令是需要执行的,试想下,当你拖拽地球的时候,重新被计算的地球的显示,以及你在这上面增加的任何几何体,都会被重新更新显示的位置,可能的话还有颜色,深度等等。也就是说,drawCommand它就是一个cesium用来做绘制操作的命令,并无更多深奥的解释。
将从以下几个必须的属性分析
cesium得drawCommand的渲染除开uniformMap这个,其余4个都是必须的,那这里为什么要加上去呢?主要是比较常用,而且当你需要与着色器内部进行数据交互的时候,查找资料找到drawCommand这个类时,绝大部分都会用到,故此也放入此文一同进行探索与研究。
new Cesium.DrawCommand({
vertexArray: vertexArray,
shaderProgram: shaderProgram,
uniformMap: uniformMap,
renderState: renderState,
pass: Cesium.Pass.OPAQUE
})
vertexArray
这是一个cesium用于描述顶点属性的一个字段,这个字段的内容有什么?先看图 最外层看,这只有一些描绘字段,关注重点,一个是indexBuffer、context、attributes,那相信对这篇文章有阅读欲望的已经不需要我过多的去解释这三个属性的意思了。我们只需要关注这个vertexArrayObject如何创建就可以了。
-
创建 翻看源码,创建的方式有挺多种,先介绍最常用的,vertexArray.fromGeometry 此API。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/eda14cff7e3b4fb0a8858c911ab0552e.png 此API需要三个参数,其他默认即可,稍微常用点的bufferUsage此API,DYNAMIC_DRAW则表示此缓冲数据经常会被使用与修改,STATIC_DRAW则表示此缓冲数据平常不咋动。这个描述是用于告知webgl内部进行优化处理的。也就是说这个在大多数情况下来说,STATIC_DRAW会更好一点,毕竟我们geometry出来后通常就调着色器,而不是要经常改生成的geometry的数据。但本人写下这篇文章的时候还没能测试过DYNAMIC_DRAW与STATIC_DRAW之间的性能差别,所以,这里仅根据官方MDN的描述做叙述。 -
下图是第二种创建模式 这个的话就比较接近原生的webgl的写法了,index 为顶点属性的存放索引。也就是说只要你愿意,第一个推进缓冲区的数据position属性对应的索引,你大可以给它改成10(举例,是不是10无关紧要)。绑定之后你要写入,你也得告诉webgl你想往哪个索引对应的缓冲数据区写入数据,这里也印证了上方获取attributeLocations为何是必须的,原因在于这个索引虽然你默认的时候它就是从0自增,但总有特定改变的时候。 综上,如果你想从顶点数据生成的时候一步到位使用此文中的第二种。如果你已经生成了geometry用此文中的第一种,反正怎么省事怎么来,先把功能做出来再说。
shaderProgram
这个类是cesium 封装的一个program类,核心功能其实就是简化shader与program的绑定,shader的编译,同时做些缓存处理。先上图,接着慢慢分析。 program在原生webgl中用于管理项目的资源。可能有点抽象,但这个印象很重要,据目前本人的知识来说,一个是管理顶点属性索引,一个是管理片元着色器与顶点着色器。 我们尽量不在原生webgl上扯太远(太远我也不会),回到它的类里。
- 如何创建一个shaderProgram
网上基本所有的文章都是通过此方法去创建的。没别的原因,主要就是省事一些。 在这个实际执行的函数里面,我们关注它所需要的参数,以及简单的看下它做了哪些工作就可。 判断是否是字符串,生成shaderSource类,在此类里面做些判断版本(如webgl2)加精度、加定义等, 接着通过关键词判断是否存在于缓存中决定是否要重新生成一个shaderProgram进行管理、编译shader内容。 到此我们可以知道,这个shaderProgram的创建如果我们要手动的生成的话,不算是灾难,但至少会麻烦很多,而且还需要手动应用上它内部做的缓存机制。探索至此,相信大家对为什么要用ShaderProgram.fromCache这个API添加新的shaderProgram有了个答案了。 第一、只需传递字符串,无需生成个ShaderSource的类,处理shaderText的内容 第二、缓存机制需自己手动实现
var shaderProgram = Cesium.ShaderProgram.fromCache({
context: context,
vertexShaderSource: vertexShaderSource,
fragmentShaderSource: fragmentShaderSource,
attributeLocations: attributeLocations
})
uniformMap
这个属性是用于设置uniform的,有一个特别需要注意的东西则是创建的格式。
var uniformMap = {
frameNumber() {
return i++;
},
randomNum() {
return Math.random() * 1000
}
}
其实也没啥好说的,唯一值得说的一点就是为何 使用 function return这个值,原因跟vue里的data return 是差不多的一个道理,主要是防止多个uniformMap 对象共用一个属性,造成数据污染,特地设置成的用函数返回,保持作用域的纯净。 简单看下源码,此uniformMap通过AutomaticUniform 这个类去完成uniform再着色器中的声明,从webgl的方面来说,要想使用一个uniform变量,一个是着色器部分得声明此变量,第二个则是对此uniform赋值。 包括各种得czm前缀的uniform 设置 也是通过这个类去加载的,当然,实际上这个类在内部就已经定义有一个常量用于装载这些uniform 而uniformMap只是在往这个AutomaticUniforms的添加描述的属性以及值而已。这其中也解释了uniformMap的工作原理:借由一个描述uniform的对象,将实际运行在着色器中的代码增加声明,重写着色器中的代码,由shaderProgram进行编译,最终将该值传递至着色器中。
renderState
|