WebGL 绘制一个矩形

优质
小牛编辑
134浏览
2023-12-01

本节课通过绘制一个矩形边框效果,对WebGL整个渲染流程有一个简单认知。

学习建议

学习本节课,建议先结合注释看看案例源码,对于不熟悉的WebGL API可以在MDN搜索文档,不过刚开始学习,没必要去掌握每一个WebGL API,把主要精力放在理解WebGL的整个渲染流程上面,如果你能建立渲染管线的概念,自然对WebGL系统会有一个基本的认知。

源码体验测试

//类型数组构造函数Float32Array创建顶点数组
// 矩形四个顶点坐标的数据
var data=new Float32Array([0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5]);
  • 源码第51行new Float32Array([0.5,0.5,...顶点数组数据的数值随意更改大小,范围控制在0.0~1.0之间,观察绘制出的图形轮廓变化,你会发现数组的8个子元素表示的是四边形的四个点顶位置。
//开始绘制图形
gl.drawArrays(gl.LINE_LOOP,0,4);
  • 第65行代码,drawArrays()方法的第3个参数4,更改为3或2,观察图形轮廓变化。可以看出第三个参数表示是的绘制前几个点,两点确定一条直线,四个顶点绘制并且闭合后是矩形,如果前三个点组成矩形,两个点只能构成直线。

  • 第65行代码,drawArrays方法的第2个参数0,更改为1,会发现报错,canvas画布也不显示。其实是因为第二个参数表示从第几个点开始绘制,1表示从第二个开始,第三个据说不能再填写4,最大只能有3个点,因为第一个点没有参与绘制

  • 第65行代码,drawArrays方法的第1个参数LINE_LOOP,分别更改为LINESLINE_STRIPTRIANGLES,可以看到不同的效果,第一个参数成为绘制模式mode,不同的模式有不同的意思,可以查询WebGL中文文档gl.drawArrays()获取详细解释。

attribute关键字

这节课首先给大家引入一个新的着色器语法,声明顶点相关数据的时候需要用到attribute关键字。

attribute vec4 apos;声明的变量apos表示矩形所有顶点的位置坐标。WebGL着色器语言之所以规定attribute这样一个关键字,目的是为了javascript可以调用相关的WebGL API把顶点相关数据从javascript传递给顶点着色器attribute声明的变量。

//attribute声明vec4类型变量apos
attribute vec4 apos;

你可以看到案例代码中类型数组var data=new Float32Array([0.5,0.5,-0.5...包含了矩形四个顶点的xy坐标。

//类型数组构造函数Float32Array创建顶点数组
var data=new Float32Array([0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5]);

javascript会调用相关的WebGL API通过下面的代码把类型数组data中包含的顶点位置坐标数据传递给顶点着色器中attribute关键字声明的变量apos

//获取顶点着色器的位置变量apos,即aposLocation指向apos变量。
var aposLocation = gl.getAttribLocation(program,'apos');
...
...
//创建缓冲区对象
var buffer=gl.createBuffer();
//绑定缓冲区对象,激活buffer
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
//顶点数组data数据传入缓冲区
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
//缓冲区中的数据按照一定的规律传递给位置变量apos
gl.vertexAttribPointer(aposLocation,2,gl.FLOAT,false,0,0);
//允许数据传递
gl.enableVertexAttribArray(aposLocation);

代码执行流程简述

  • 代码执行到第46行var program=initShader(...),会调用第68行的初始化着色器函数initShader(),该函数第一个案例代码中用到过,以后也会经常使用,暂时可以把它当成黑箱,知道总体作用就行。 执行该函数后,会返回一个程序program对象,同时顶点着色器的位置变量apos会 与program建立联系,你可以把apos理解为对象program的属性。
//初始化着色器
var program = initShader(gl,vertexShaderSource,fragShaderSource);
  • 代码执行到第48行,通过getAttribLocation()方法使当前定义的变量aposLocation指向apos变量,方法的第一个参数是对象program,第二个参数是顶点着色器位置变量apos,并使用引号标识。
//获取顶点着色器的位置变量apos,即aposLocation指向apos变量。
var aposLocation = gl.getAttribLocation(program,'apos');
  • 第51行代码new Float32Array([0.5,...定义的是矩形四个顶点的顶点坐标,仅定义了x和y轴坐标,8个元素存入数组,z轴坐标未定义,z轴方向垂直屏幕,如果图形没有旋转平面显示不受z影响,关于WebGL的坐标系问题可以先不关心。 当浏览器运行这句代码时,会在内存上开辟一个区域,初始化语句重定义的矩形顶点数据。
//类型数组构造函数Float32Array创建顶点数组
var data=new Float32Array([0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5]);
  • 第53~62行代码的作用总体上是把内存中顶点数据输入显存,这样可以提高图形的处理效率,第60行代码gl.vertexAttribPointer(aposLocation,2,gl.FLOAT,false,0,0);设定的是当执行第65行代码绘制函数gl.drawArrays()时候,如何提取数据,该语句的第二个参数2表达的意思是两个数组为一组, 8个元素也就是总共四组,逐组传递给apos变量,查看顶点着色器中代码attribute vec4 apos;可以知道apos是vec4类型数据,也就是有四个参数的向量,这样的话缺少两个数值元素, 这种情况下,一般第三个代表z轴的坐标值默认为0.0,第四个参数默认为1.0,数据逐组传递的过程就蕴含着GPU渲染管线逐顶点处理数据的概念。
//创建缓冲区对象
var buffer=gl.createBuffer();
//绑定缓冲区对象,激活buffer
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
//顶点数组data数据传入缓冲区
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
//缓冲区中的数据按照一定的规律传递给位置变量apos
gl.vertexAttribPointer(aposLocation,2,gl.FLOAT,false,0,0);
//允许数据传递
gl.enableVertexAttribArray(aposLocation);
  • 第65行代码gl.drawArrays(gl.LINE_LOOP,0,4);相当于最后的发令枪,命令GPU开始逐顶点处理数据,并安装一定的方式处理顶点,生成最终像素数据,第一个参数控制的是如何根据点生成像素。
//开始绘制图形
gl.drawArrays(gl.LINE_LOOP,0,4);

drawArrays整体执行顺序

drawArrays整体执行顺序

WebGL渲染管线示意图如下所以,除了本小节,本章同样有一个重要内容就是你需要建立WebGL渲染管线的概念,通过本节课的学习,你会了解到WebGL渲染管线上顶点着色器和片元着色器两个功能单元,渲染管线整条流水线上其它的功能单元你可能暂时还没有任何概念,这没有关系,暂时现有一个印象就可以,后面的课程会逐步揭开WebGL渲染管线的面纱。

渲染管线

硬件相关

  • 着色器语言编写的程序称为着色器程序(shader program),在GPU顶点着色器单元上执行的是顶点着色器程序, 在GPU片元着色器单元上执行的是片元着色器程序。

顶点着色器

//attribute声明vec4类型变量apos
attribute vec4 apos;
void main() {
  //顶点坐标apos赋值给内置变量gl_Position
  //逐顶点处理数据
  gl_Position = apos;
}

片元着色器

void main() {
  // 逐片元处理数据,所有片元(像素)设置为红色
  gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
  • 可编程顶点处理器(Programmable Vertex Processor)又称为顶点着色器,用来执行顶点着色器程序

  • 可编程片元处理器(Programmable Fragment Processor)又称为片元着色器,用来执行片元着色器程序

  • GPU中有各种专门的寄存器,比如用来接收顶点坐标数据的寄存器是输入寄存器,从数据类型的角度看属于浮点寄存器,用来临时存储浮点数; 存储输出到显示器像素的帧缓存是输出寄存器,从处理速度的角度看是数据缓冲寄存器,GPU处理数据的速度要比显示器扫描帧缓存中像素数据的速度要快得多

  • 显示器像素是显示器可以通过RGB值控制的最小单位,一幅图像是由大量像素点累积显示。着色器中的颜色定义会反映在显示器中

  • 显示器的分辨率就是显示器长度方向像素点的个数X显示器宽度方向像素点的个数

  • 屏幕相邻的两个像素单元的距离就是点距,点距越小显示效果越好,一般现在显示器0.2mm~0.4mm之间