WebGL绘制一个矩形
源码下载- 理解逐顶点、逐片元
- 绘制模式
- 图元装配
- 光栅化
知识点
本案例的讲解建立第一案例的基础上,了解GPU逐顶点处理数据的流程,学习相关的API
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 </head> 6 <body> 7 <canvas id="webgl" width="500" height="500" style="background-color: #0d72da"></canvas> 8 <script> 9 var canvasElement=document.getElementById('webgl'); 10 var gl=canvasElement.getContext('webgl'); 11 //顶点着色器源码 12 var vertexShaderSource = '' + 13 //attribute声明vec4类型变量apos 14 'attribute vec4 apos;'+ 15 'void main(){' + 16 //顶点坐标apos赋值给内置变量gl_Position 17 ' gl_Position =apos;' + 18 '}'; 19 //片元着色器源码 20 var fragShaderSource = '' + 21 'void main(){' + 22 ' gl_FragColor = vec4(1.0,0.0,0.0,1.0);' + 23 '}'; 24 //初始化着色器 25 var program = initShader(gl,vertexShaderSource,fragShaderSource); 26 //获取顶点着色器的位置变量apos ,即aposLocation指向apos变量。 27 var aposLocation = gl.getAttribLocation(program,'apos'); 28 29 //类型数组构造函数Float32Array创建顶点数组 30 var data=new Float32Array([0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5]); 31 32 //创建缓冲区对象 33 var buffer=gl.createBuffer(); 34 //绑定缓冲区对象 35 gl.bindBuffer(gl.ARRAY_BUFFER,buffer); 36 //顶点数组data数据传入缓冲区 37 gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW); 38 //缓冲区中的数据按照一定的规律传递给位置变量apos 39 gl.vertexAttribPointer(aposLocation,2,gl.FLOAT,false,0,0); 40 //允许数据传递 41 gl.enableVertexAttribArray(aposLocation); 42 43 //开始绘制图形 44 gl.drawArrays(gl.LINE_LOOP,0,4); 45 46 //声明初始化着色器函数 47 function initShader(gl,vertexShaderSource,fragmentShaderSource){ 48 var vertexShader = gl.createShader(gl.VERTEX_SHADER); 49 var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); 50 gl.shaderSource(vertexShader,vertexShaderSource); 51 gl.shaderSource(fragmentShader,fragmentShaderSource); 52 gl.compileShader(vertexShader); 53 gl.compileShader(fragmentShader); 54 var program = gl.createProgram(); 55 gl.attachShader(program,vertexShader); 56 gl.attachShader(program,fragmentShader); 57 gl.linkProgram(program); 58 gl.useProgram(program); 59 return program; 60 } 61 </script> 62 </body> 63 </html>
体验测试
- 第30行顶点数组数据的数值随意更改大小,范围控制在0.0~1.0之间,观察绘制出的图形轮廓变化,你会发现数组的8个子元素表示的是四边形的四个点顶位置。
- 第44行代码,drawArrays方法的第3个参数4,更改为3或2,观察图形轮廓变化。可以看出第三个参数表示是的绘制前几个点,两点确定一条直线,四个顶点绘制并且闭合后是矩形,如果前三个点组成矩形,两个点只能构成直线
- 第44行代码,drawArrays方法的第2个参数0,更改为1,会发现报错,canvas画布也不显示。其实是因为第二个参数表示从第几个点开始绘制,1表示从第二个开始,第三个据说不能再填写4,最大只能有3个点,因为第一个点没有参与绘制
- 第44行代码,drawArrays方法的第1个参数LINE_LOOP,分别更改为LINES、LINE_STRIP、TRIANGLES,可以看到不同的效果,第一个参数成为绘制模式mode,不同的模式有不同的意思,可以查询WebGL文档获取详细解释。
代码执行流程简述
- 代码执行到第25行,会调用第47行的初始化着色器函数,该函数第一个案例代码中用到过,以后也会经常使用,暂时可以把它当成黑箱,知道总体作用就行。 执行该函数后,会返回一个程序program对象,同时顶点着色器的位置变量apos会 与program建立联系,你可以把apos理解为对象program的属性
- 代码执行到第27行,通过getAttribLocation()方法使当前定义的变量aposLocation指向apos变量,方法的第一个参数是对象program,第二个参数是顶点着色器位置变量apos,并使用引号标识。
- 第30行代码定义的是矩形四个顶点的顶点坐标,仅定义了x和y轴坐标,8个元素存入数组,z轴坐标未定义,z轴方向垂直屏幕,如果图形没有旋转平面显示不受z影响,关于WebGL的坐标系问题可以先不关心。 当浏览器运行这句代码时,会在内存上开辟一个区域,初始化语句重定义的矩形顶点数据。
- 第33~41行代码的作用总体上是把内存中顶点数据输入显存,这样可以提高图形的处理效率,第39行代码设定的是当执行第44行代码时候,如何提取数据,该语句的第二个参数2表达的意思是两个数组为一组, 8个元素也就是总共四组,逐组传递给apos变量,查看第14行代码可以知道apos是vec4类型数据,也就是有四个参数的向量,这样的话缺少两个数值元素, 这种情况下,一般第三个代表z轴的坐标值默认为0,第四个参数默认为1,数据逐组传递的过程就蕴含着GPU渲染管线逐顶点处理数据的概念。
- 第41行代码相当于最后的发令枪,命令GPU开始逐顶点处理数据,并安装一定的方式处理顶点,生成最终像素数据,第一个参数控制的是如何根据点生成像素。
drawArrays整体执行顺序
内存 顶点数据 |
显存 缓冲区 |
顶点 着色器 |
片元 着色器 |
帧 缓冲区 |
显示器 |
- 顶点着色器执行main函数中语句gl_Position =apos;,逐顶点获得顶点坐标数据,有四个点意味着赋值执行四次,这个过程就是逐顶点
- 顶点数据获得后,会进行图元装配,起作用的就是drawArrays方法的第一个参数绘制模式mode,然后光栅化得到的就是片元framgment,你可把片元理解成还没有定义颜色的显示器相应位置的像素rgb值,尽管这么理解不完美
- 光栅化后得到片元数据,片元着色器会执行main函数中语句gl_FragColor = vec4(1.0,0.0,0.0,1.0);,每一个片元依次添加颜色,这里定义的是红色,处理过程就是逐片元处理。
- 处理后获得的像素颜色数据可能还要经过一些环节,为了简化问题,你暂时可以理解为这些片元处理后得到的一系列像素数据都存储在显卡的帧缓冲区中,你可简单理解为一张图片是一帧,显示器会按照一定的频率扫描并显示这些数据, 界面刷新频率60HZ最常见,人的眼睛有视觉暂留效应,只要刷新频率不太低,就不会感觉到卡顿,有些视频单位时间内播放的帧数太少,大家会感到很不流畅。
- 着色器语言编写得程序成为着色器程序(shader program),在顶点着色器上执行的是顶点着色器程序,也就是代码中注释的顶点着色器源码12~18行, 在片元着色器上执行的是片元着色器程序,也就是代码中注释的片元着色器源码20~23行
- 可编程顶点处理器(Programmable Vertex Processor)又称为顶点着色器,用来执行顶点着色器程序
- 可编程片元处理器(Programmable Fragment Processor)又称为片元着色器,用来执行片元着色器程序
- GPU中有各种专门的寄存器,比如用来接收顶点坐标数据的寄存器是输入寄存器,从数据类型的角度看属于浮点寄存器,用来临时存储浮点数; 存储输出到显示器像素的帧缓存是输出寄存器,从处理速度的角度看是数据缓冲寄存器,GPU处理数据的速度要比显示器扫描帧缓存中像素数据的速度要快得多
- 显示器像素是显示器可以通过RGB值控制的最小单位,一幅图像是由大量像素点累积显示。着色器中的颜色定义会反映在显示器中
- 显示器的分辨率就是显示器长度方向像素点的个数X显示器宽度方向像素点的个数
- 屏幕相邻的两个像素单元的距离就是点距,点距越小显示效果越好,一般现在显示器0.2mm~0.4mm之间