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>

体验测试

代码执行流程简述

  1.   代码执行到第25行,会调用第47行的初始化着色器函数,该函数第一个案例代码中用到过,以后也会经常使用,暂时可以把它当成黑箱,知道总体作用就行。 执行该函数后,会返回一个程序program对象,同时顶点着色器的位置变量apos会 与program建立联系,你可以把apos理解为对象program的属性
  2.   代码执行到第27行,通过getAttribLocation()方法使当前定义的变量aposLocation指向apos变量,方法的第一个参数是对象program,第二个参数是顶点着色器位置变量apos,并使用引号标识。
  3.   第30行代码定义的是矩形四个顶点的顶点坐标,仅定义了x和y轴坐标,8个元素存入数组,z轴坐标未定义,z轴方向垂直屏幕,如果图形没有旋转平面显示不受z影响,关于WebGL的坐标系问题可以先不关心。 当浏览器运行这句代码时,会在内存上开辟一个区域,初始化语句重定义的矩形顶点数据。
  4.   第33~41行代码的作用总体上是把内存中顶点数据输入显存,这样可以提高图形的处理效率,第39行代码设定的是当执行第44行代码时候,如何提取数据,该语句的第二个参数2表达的意思是两个数组为一组, 8个元素也就是总共四组,逐组传递给apos变量,查看第14行代码可以知道apos是vec4类型数据,也就是有四个参数的向量,这样的话缺少两个数值元素, 这种情况下,一般第三个代表z轴的坐标值默认为0,第四个参数默认为1,数据逐组传递的过程就蕴含着GPU渲染管线逐顶点处理数据的概念。
  5.   第41行代码相当于最后的发令枪,命令GPU开始逐顶点处理数据,并安装一定的方式处理顶点,生成最终像素数据,第一个参数控制的是如何根据点生成像素。

drawArrays整体执行顺序



内存

顶点数据


显存

缓冲区


顶点

着色器


片元

着色器




缓冲区



显示器
  1. 顶点着色器执行main函数中语句gl_Position =apos;,逐顶点获得顶点坐标数据,有四个点意味着赋值执行四次,这个过程就是逐顶点
  2. 顶点数据获得后,会进行图元装配,起作用的就是drawArrays方法的第一个参数绘制模式mode,然后光栅化得到的就是片元framgment,你可把片元理解成还没有定义颜色的显示器相应位置的像素rgb值,尽管这么理解不完美
  3. 光栅化后得到片元数据,片元着色器会执行main函数中语句gl_FragColor = vec4(1.0,0.0,0.0,1.0);,每一个片元依次添加颜色,这里定义的是红色,处理过程就是逐片元处理。
  4. 处理后获得的像素颜色数据可能还要经过一些环节,为了简化问题,你暂时可以理解为这些片元处理后得到的一系列像素数据都存储在显卡的帧缓冲区中,你可简单理解为一张图片是一帧,显示器会按照一定的频率扫描并显示这些数据, 界面刷新频率60HZ最常见,人的眼睛有视觉暂留效应,只要刷新频率不太低,就不会感觉到卡顿,有些视频单位时间内播放的帧数太少,大家会感到很不流畅。