阅读需知
webGL是使用js编写的openGL。cesium本身是基于webGL绘制三维实体的,是webGL的地球引擎。WebGL利用的是canvas的绘图区域。也就是说,使用WebGL的网页,HTML里面肯定含有canvas标签。cesium的实体primitve的mateiral材质可以使用canvas提供的材质,也可以直接使用着色器绘制。canvas的绘制是基于webGL的。着色器属于webGL的范畴,用于绘制特殊的纹理材质和图元。
固定渲染管线
固定渲染管线,简单来说,就是3d渲染所进行的一连串的计算流程,就像流水线一样。固定渲染管线中,模型,视图,投影的坐标变换都会替我们完成。不需要理解细节,只需要知道所有的这些坐标变换都包含在里面,都会帮我们计算好。
如果有了固定渲染管线,编写程序就比较容易了,因为所有的变换都是由固定渲染管线来完成的,但是缺点就是自由度低。固定渲染管线只能完成一些最基本的操作,如果想要做一些特殊的处理,就比较麻烦了。
WebGL中不存在固定渲染管线。也就是说,坐标变换必须全部由自己来做。而且,这个记述了坐标变换的机制就叫做着色器(Shader)。
这样可以由程序员控制的机制叫做可编辑渲染管线。而着色器又有 处理几何图形顶点的顶点着色器(Vertex shader、vs)和处理像素的片段着色器(Fragment shader,fs)两种类型。
着色器GLSL使用C语言为基础,并且有自己独立的语法,它是一段在GPU上运行的程序,并不是脚本,使用过编译语言的应该明白,C要编译成一个exe需要经过编译、链接这两个步骤,同样的,着色器程序也需要这两个步骤。
着色器引用
着色器就是一个代码段,将这段代码放进cesium或者js代码段中即可。那么该如何表示着色器代码呢?目前我所知有两种方式: 字符串赋值法和js文件保存法; 。
js文件方式
将代码段保存为js文件,为了在javascript中可以调用,给script标签加上了id属性。另外,type属性是和javascript不同的,不要误认为是javascript代码。
<script id="vshader" type="x-shader/x-vertex">
var vs = `
attribute vec3 position3DHigh;
attribute vec3 position3DLow;
void main()
{
vec4 localPoition = vec4(position3DHigh + position3DLow,1.0);
gl_Position = czm_modelViewProjection *localPoition;
}
`
</script>
<script id="fshader" type="x-shader/x-fragment">
※片段着色器
</script>
字符串方式
需要使用符号``将代码段括起来。vs变量可以直接引用
var vs = `
attribute vec3 position3DHigh;
attribute vec3 position3DLow;
void main()
{
vec4 localPoition = vec4(position3DHigh + position3DLow,1.0);
gl_Position = czm_modelViewProjection *localPoition;
}
`
var appearance:=new Cesium.MaterialAppearance({
material: materialCircle,
closed: true,
vertexShaderSource: vs,
fragmentShaderSource: fs
}),
顶点着色器
顶点着色器和片段着色器必然同时出现,并且首先被调用的是顶点着色器。
顶点着色器用于处理顶点信息,可以把顶点相关的所有情报都传给顶点着色器。比如,顶点的位置,顶点法线,纹理坐标,顶点颜色等等。
不管是顶点着色器还是片段着色器,都必须定义一个main函数,函数里记录即将要做的处理。而且,顶点着色器中,必须要把顶点信息传给一个叫做gl_Position的变量,它表示当前在处理的那个顶点在处理结束之后的位置,是一个GLSL内置的变量。
顶点修饰符attribute
attribute只能存在于顶点着色器中, 用这个修饰符来定义的变量(比如下面的position),是用来接收顶点信息的。也就是说,WebGL程序中定义一个position,做一些处理之后,传给着色器。需要补充的是,attribute修饰符是用来接收不同顶点传来的不同信息。如果存在很多个顶点的话,这些顶点的位置是不同的,需要分别使用attribute进行定义。
attribute vec3 position;
attribute vec3 position3DHigh;
attribute vec3 position3DLow;
void main(void) {
gl_Position = position*2;
}
坐标变换unifrom
顶点着色器是用于处理顶点坐标的,顶点相关的处理就是坐标变换,所以模型变换,视图变换,投影变换这三个变换也是顶点着色器的工作之一。
前面章节学习过,坐标变换时需要传递一个用于变换的矩阵modelMatrix,attribute是用来声明变量的用于处理不同顶点的不同信息,而坐标变换矩阵对于所有顶点来说都是相同的,所有使用unifrom修饰符定义。
attribute vec3 position;
uniform mat4 mvpMatrix;
void main(void) {
gl_Position = mvpMatrix * position;
}
片段着色器
以上使用顶点着色器我们将模型整体轮廓绘制出来了,接下来需要使用片段着色器对模型的整体色彩进行绘制。其中片段着色器处理各个点的色彩需要预先知道每个顶点的位置,而连接顶点着色器和片段着色器的桥梁关键修饰符就是varying。
桥梁varying
顶点着色器部分代码片段:
attribute vec4 position;
attribute vec4 color;
uniform mat4 mvpMatrix;
varying vec4 vColor
void main(void) {
vColor = color;
gl_Position = mvpMatrix * position;
}
片段着色器接收通过varying修饰符所定义的变量vColor,其中类似于顶点着色器,片段着色器也有内置变量gl_FragColor,只是gl_position是必须要赋值的,gl_FragColor不是必须有的。
varying vec4 vColor;
void main(void)
{
gl_FragColor = vColor;
}
除了以上提到的三个变量修饰符,还有另外两个,概括为下表:
| 修饰符 | 说明 |
| none | (默认的可省略)本地变量,可读可写,函数的输入参数既是这种类型 |
| const | 声明变量或函数的参数为只读类型 |
| attribute | 只能存在于vertex shader中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据 |
| uniform | 在运行时shader无法改变uniform变量, 一般用来放置程序传递给shader的变换矩阵,材质,光照参数等等. |
| varying | 主要负责在vertex 和 fragment 之间传递变量 |
数据类型
上文的示例代码中出现的vec4,mat4代表的是变量的数据类型,glsl中更多的数据类型可以见下表:
| 类型 | 说明 |
| void | 空类型,即不返回任何值 |
| bool | 布尔类型 true,false |
| int | 带符号的整数 |
| float | 带符号的浮点数 |
| vec2, vec3, vec4 | n维浮点数向量 |
| bvec2, bvec3, bvec4 | n维布尔向量 |
| ivec2, ivec3, ivec4 | n维整数向量 |
| mat2, mat3, mat4 | 2x2, 3x3, 4x4 浮点数矩阵 |
| sampler2D | 2D纹理 |
| samplerCube | 盒纹理 |
向量的分量访问
上表中 vec*与mat*是高频使用的数据类型,vec*表示的是向量,vec2就代表一个2维的向量。mat*表示的是方阵,如果是mat3的话,就表示一个3x3的方阵。
向量(vec2,vec3,vec4)往往有特殊的含义,可能代表了一个空间坐标(x,y,z,w),一个颜色(r,g,b,a)或者 一个纹理坐标(s,t,p,q) 所以glsl提供了一些人性化的分量访问方式 :
vector.xyzw 其中xyzw 可以任意组合
vector.rgba 其中rgba 可以任意组合
vector.stpq 其中stpq 可以任意组合
vec4 v=vec4(1.0 ,2.0 ,3.0 ,1.0 ); vec3 xyz = v.xyz;// vec3(1.0,2.0,3.0) vec3 xyz1 = vec(v[0 ],v[1 ],v[2 ]);// vec3(1.0,2.0,3.0) vec3 rgb = v.rgb;// vec3(1.0,2.0,3.0) vec4 xyzw = v.xyzw;// vec4(1.0,2.0,3.0,1.0); vec4 rgba = v.rgba;// vec4(1.0,2.0,3.0,1.0);
glsl内置变量
除了刚才提到gl_position和gl_FragColor是内置的变量,glsl还有很多内置的变量。这些特殊的内置变量用于和硬件进行沟通。他们大致分成两种,一种是input类型,负责向硬件(渲染管线)发送数据。另一种是output类型,负责向程序回传数据,以便编程时需要。
vertex Shader 中
output 类型的内置变量:
|
变量 |
说明 |
单位 |
|
gl_Position; |
gl_Position 放置顶点坐标信息 |
vec4 |
|
gl_PointSize; |
gl_PointSize 需要绘制点的大小,(只在gl.POINTS模式下有效) |
float |
fragment Shader 中
input 类型的内置变量:
|
变量 |
说明 |
单位 |
|
gl_FragCoord; |
片元在framebuffer画面的相对位置 |
vec4 |
|
gl_FrontFacing; |
标志当前图元是不是正面图元的一部分 |
bool |
|
gl_PointCoord; |
经过插值计算后的纹理坐标,点的范围是0.0到1.0 |
vec2 |
output 类型的内置变量:
|
变量 |
说明 |
单位 |
|
gl_FragColor; |
设置当前片点的颜色 |
vec4 RGBA color |
|
gl_FragData[n] |
设置当前片点的颜色,使用glDrawBuffers数据数组 |
vec4 RGBA color |
着色器与cesium结合
以上我们学会了如何编写一段简单的着色器代码,接下来我们将了解如何在cesium中使用着色器进行模型的绘制。
本文介绍了WebGL中的着色器GLSL基础知识,包括顶点着色器和片段着色器的使用,以及如何在Cesium中结合着色器绘制3D模型。着色器是可编辑渲染管线的一部分,允许程序员自定义坐标变换和颜色处理。GLSL基于C语言,通过attribute、uniform和varying修饰符传递和处理顶点信息。
585

被折叠的 条评论
为什么被折叠?



