着色器glsl基础

本文介绍了WebGL中的着色器GLSL基础知识,包括顶点着色器和片段着色器的使用,以及如何在Cesium中结合着色器绘制3D模型。着色器是可编辑渲染管线的一部分,允许程序员自定义坐标变换和颜色处理。GLSL基于C语言,通过attribute、uniform和varying修饰符传递和处理顶点信息。

阅读需知

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, vec4n维浮点数向量  
bvec2, bvec3, bvec4n维布尔向量 
ivec2, ivec3, ivec4n维整数向量  
mat2, mat3, mat42x2, 3x3, 4x4 浮点数矩阵  
sampler2D2D纹理  
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中使用着色器进行模型的绘制。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值