绘制一个点
HelloPoint1
如果要在绘图区域中心绘制一个红点,
理论上只需要两步:
- 指定点的颜色
- 指定点的位置和大小
1 | gl.drawColor(1.0, 0.0, 0.0, 1.0); |
不幸的是,WebGL依赖一种称为着色器(shader)的绘图机制,
shader强大且复杂,仅用一条简单绘图命令无法操作。
1 |
|
1 | // 顶点着色器程序 |
什么是着色器?
- 描述范围: 顶点特性(如位置、颜色等)
- 顶点(vertex): 二维或三维空间中的一个点(如端点、交点等)
- 描述范围: 进行逐片元处理过程(如光照等)
- 片元(fragment): 类似于像素(图像的单元)
shader程序以String的形式嵌入在JavaScript文件中。
1 | var VSHADER_SOURCE = |
1 | var FSHADER_SOURCE = |
1 | function main() { |
1.获取canvas元素
1 | let canvas = document.getElementById('webgl'); |
2.获取WebGL绘图上下文
1 | let gl = getWebGLContext(canvas); |
3.初始化着色器
1 | initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE); |
该函数被定义在 cuon.util.js 中。
- 着色器运行在WebGL系统中,而不是JavaScript系统中。
- 片元着色器接收到的是经过光栅化处理后的片元值。
- WebGL程序包括运行于Browser的JS和运行于WebGL的shader两个部分
4.设置canvas背景色
1 | gl.clearColor(0.0,0.0,0.0,1.0); |
5.清除canvas
1 | gl.clear(gl.COLOR_BUFFER_BIT); |
6.绘图
1 | gl.drawArrays(gl.POINTS,0,1) |
要画一个点,你需要3个关键信息:
- 位置
- 尺寸
- 颜色
shader程序本身必须包含一个 main 函数。
注意:gl_Position必须赋值,gl_PointSize可选,默认值为1.0
表示浮点数,因此必须使用浮点形式的数字进行赋值。
这样写就会出错:
1 | gl_PointSize = 10; |
矢量(vector),表示由4个浮点数组成的矢量,
shader提供了内置函数 vec4() 创建vec4类型的变量。
有4个分量组成的矢量被称为齐次坐标。
片元就是显示在屏幕上的一个像素。
gl_FragColor 是片元着色器唯一的内置变量。
drawArrays() 可以用来绘制各种图形。
1 | gl.drawArrays(gl.POINTS,0,1); |
- 第一个参数(gl.POINTS):表示绘制单点
- 第二个参数(0):从第1个顶点开始绘制
- 第三个参数(1):表示仅绘制1个点
一旦Vertex_shader执行完毕,Fragment_shader就开始执行
WebGL坐标系统
WebGL使用的是三维坐标系统(笛卡尔坐标系)。
WebGL默认使用右手坐标系,
但实际上,WebGL本身不是左手也不是右手坐标系,要复杂得多。
需要将WebGL的坐标系映射到canvas绘图区中。
坐标对应关系如下:
WebGL坐标 | canvas坐标 |
---|---|
( 0.0, 0.0, 0.0) | 中心点 |
(-1.0, 0.0, 0.0) | 左边缘 |
( 1.0, 0.0, 0.0) | 右边缘 |
( 0.0, -1.0, 0.0) | 下边缘 |
( 0.0, 1.0, 0.0) | 上边缘 |
HelloPoint2
- 版本1: 点位硬编码在Vertex Shader中
- 版本2: 点位坐标从JS传到Shader程序中
要实现从JavaScript程序向Vertex_Shader传输位置信息,
有两种方式可以实现(使用哪一个取决于需传输的数据本身):
传输的是那些与顶点相关的数据。
传输的是那些与顶点无关的数据。
attribute变量实际上是一种 GLSL ES 变量,
功能就是被用来 从外部向Vertex_Shader内部传输数据 。
- 声明: 在Vertex_Shader中声明attribute变量。
- 赋值: 将attribute变量赋值给gl_Position变量。
- 传输: 向attribute变量传输数据。
1 |
|
1 | // 顶点着色器 |
步骤一:声明
attribute又称 存储限定符 (storage qualifier)。
attribute变量必须声明成全局变量,
attribute变量声明格式如下:
<存储限定符> <类型> <变量名>
步骤二:获取
每个变量都具有一个存储地址,
以便通过存储地址向变量传输数据。
用于获取attribute变量的地址。
其接收2个参数:
只要引用gl.program即可,
包括了Vertex_Shader和Frag_Shader,
由 initShader() 函数创建,
因此必须在initShader函数调用之后访问。
参数2:attribute变量的存储地址
步骤三:赋值
如果对于vec4类型的变量通过vertexAttrib3f传参,
自然会省略掉1个参数,则默认为1.0。
gl.vertextAttrib[1-4]f有一系列函数,
专门负责从JavaScript向Vertex_Shader中的attribute变量传参。
gl.vertextAttrib[1-4]f也提供矢量版本gl.vertextAttrib[1-4]fv:
- 名字以v结尾
- 接受类型化数组参数
1 | var position = new Float32Array([1.0, 2.0, 3.0, 1.0]); |
与OpenGL ES 2.0一致。
由三个部分组成:
- 基础函数名
- 参数个数
- 参数类型