优雅的学习webgl(1)—从0开始构造你的第一个webgl程序


    学习webgl也有小半年的时间了,有了一些心得和体会,在这里作一个记录,整个系列的代码都会给出,这篇文章是这个系列的第一篇文章,带你走进webgl的世界。javascript

  • 什么是webgl
  • 用webgl画点
  • 用webgl实现一个彩色正方形

这是一个系列的文章,首发自个人博客:github.com/fortheallli…html

这个系列的源码地址为:源码的地址为: github.com/fortheallli…java

1、什么是webgl

  在介绍什么是webgl以前,咱们来看一个最简单的webgl程序。git

<html lang="en">
  <head> <title>WebGL Demo</title> <meta charset="utf-8"> </head> <body> <canvas id="glcanvas" width="640" height="480"></canvas> </body> <script> main(); // start here function main() { const canvas = document.querySelector("#glcanvas"); // Initialize the GL context const gl = canvas.getContext("webgl"); // Only continue if WebGL is available and working if (!gl) { alert("你的浏览器不支持webgl"); return; } // Set clear color to black, fully opaque gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear the color buffer with specified clear color gl.clear(gl.COLOR_BUFFER_BIT); } </script> </html>

复制代码

上述就是一个webgl的例子,作的事情很简单就是清空了webgl画布的颜色。在上述的例子中,咱们没有引入什么其余的插件,就构建了一个webgl程序,由于webgl自己就是浏览器层面的。Webgl是内嵌在浏览器中的,你没必要安装任何插件或者库,若是浏览器支持webgl,就能够经过getContext的方法建立一个webgl实例。github

const gl = canvas.getContext("webgl");
复制代码

    一提到webgl就容易跟3D渲染绘图联系在一块儿,实际上这二者并无绝对关联,webgl也能够用来绘制2D平面图形,2D动画等等。那么webgl究竟是什么呢?一句话归纳就是:web

经过绘图渲染技术OpenGL在浏览器里面进行图形渲染的技术编程

    了解过图形渲染技术的同窗都听过OpenGL等,咱们能够经过C语言,在window等平台上编写复杂和渲染出复杂的图形,经过OpenGL绘制和渲染图形有很高的平台要求以及编程语言的限制。而Webgl源自于OpenGL,从OpenGL2.0的着色器行为中诞生了适用于移动式穿戴设备的OpenGL ES标准,在这个标准下演化出了webgl,使得咱们能够经过结合javascript语言和GLSL ES着色器语言,在浏览器中绘制出复杂的图形,不须要编译也不须要引入任何插件.canvas

2、用webgl画点

    接着咱们来看如何用webgl来绘制一个完整的图案,绘制图案跟上一小节最简单的清空画布的webgl程序不一样。咱们须要webgl中的两个重要的概念——着色器。     webgl的本质就是经过顶点着色器和片元着色器,将图形渲染到浏览器中。以后咱们会详细的介绍顶点着色器和片元着色器,这里能够简单的理解为顶点着色器决定了每一个顶点的位置,片元着色器决定了图形的颜色。浏览器

一、初始化着色器程序

    绘制图案以前必须进行***着色器程序初始化***,根据着色球类型建立着色器对象,将着色器对象编译后绑定到程序对象,最后编译和链接程序对象从而完整了初始化的过程,接下来就可使用程序对象来绘制图形。编程语言

    上面的两段话特别绕,总结就是:

GLSL着色器语言是以字符串的形式存在浏览器中的,为了可以将字符串编译成能够在显卡中运行的着色器程序,必须进行着色器程序初始化

在初始化着色器程序中咱们必须用到两个对象着色器对象和程序对象,咱们来简单介绍一下这二者。

  • 着色器对象: 咱们前面提到了顶点着色器和片元着色器,着色器对象就是管理顶点着色器或者片元着色器的对象
  • 程序对象: 程序对象则是管理着色器对象的容器

咱们用图来区别这二者的关系:

Lark20191204-145309

从这个图能够看出层级关系,咱们要初始化着色器程序,就是按照以下的层级关系依次来初始化。

  1. 建立着色器对象(gl.createShader())
  2. 向着色器对象中填充着色器(gl.shaderSource())
  3. 编译着色球(gl.compileShader())
  4. 建立程序对象(gl.createProgram())
  5. 为程序对象分配着色器(gl.attashShader())
  6. 链接程序对象(gl.linkProgram())
  7. 使用程序对象(gl.useProgram())

结合上面图形的层次结构,以及上述的7步初始化着色器的步骤,咱们能够来介绍着色器初始化函数initShaderProgram

function initShaderProgram(gl, vsSource, fsSource) {
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); //建立顶点着色器对象
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);//建立片元着色器对象

  // Create the shader program

  const shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);

  return shaderProgram;
}

复制代码

这就是最上层的程序对象的建立过程,至于着色器对象的建立能够经过以下函数 loadShader:

function loadShader(gl, type, source) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);

  return shader;
}

复制代码

上述咱们就完成了着色器程序的初始化,就能够在浏览器中编译GLSL ES语言渲染出图形。下面咱们来看最简单的画点

二、画一个点

    咱们上一小节将了如何初始化着色器,初始化着色器能够经过initShaderProgram方法,咱们能够用webgl来画一个最简单的size为10的点

首先经过字符串的方式定义顶点着色器和片元着色器:

const vsSource = ` ashouttribute vec4 aVertexPosition; uniform mat4 uModelViewMatrix; uniform mat4 uProjectionMatrix; void main() { gl_Position = vec4(0.0,0.0,0.0,1.0); gl_PointSize = 10.0; } `;

  // Fragment shader program

  const fsSource = ` void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); } `;
复制代码

而后将这两个字符串传入initShaderProgram程序,就完成了着色器初始化。

const shaderProgram = initShaderProgram(gl, vsSource, fsSource)

复制代码

最后清空画布,并使用这个着色器程序开始画图:

gl.clearColor(0.0, 0.0, 0.0, 1.0);  
  gl.clearDepth(1.0);               
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
  gl.useProgram(shaderProgram);
  gl.drawArrays(gl.POINTS,0,1);
复制代码

这样就在浏览器中画出了一个点。

Lark20191204-154158

源码的地址为: github.com/fortheallli…

3、用webgl实现一个彩色正方形(选择性阅读)

    最后咱们来实现一个较为复杂的例子,用webgl来画一个正方形。咱们能够经过4次每次画一个点,画4个点,而后将这4个点连起来就成为了一个正方形,此外若是咱们要一次性的画出4个点并连成正方形,就须要使用缓冲区。

咱们能够简单理解,缓冲区保存了不少信息,咱们能够读取缓冲区的信息,在一次绘制中绘出咱们想要的图形。

咱们来看建立一个缓冲区的步骤:

  1. 建立缓冲区对象(gl.createBuffer())
  2. 绑定缓冲区对象(gl.bindBuffer())
  3. 将数据写入缓冲区对象(gl.bufferData())
  4. 将缓冲区对象分配给一个attribute变量(gl.vertexAttribPointer())
  5. 开启attribute变量(gl.enableVertexAttribArray())

这个五步能够简记为:建立-绑定-写入-分配-开启这么几步,而且咱们要使用缓冲区对象这五步是必不可免的.

咱们能够定义initBuffers方法来建立缓冲区,咱们能够分别建立一个顶点缓冲区(用于读取图形的顶点坐标)以及片元缓冲区(用于读取每一个片元的颜色信息)

function initBuffers(gl) {
  //顶点缓冲区
  const positionBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

  const positions = [
     1.0,  1.0,
    -1.0,  1.0,
     1.0, -1.0,
    -1.0, -1.0,
  ];

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
  var colors = [
    1.0,  1.0,  1.0,  1.0,    // white
    1.0,  0.0,  0.0,  1.0,    // red
    0.0,  1.0,  0.0,  1.0,    // green
    0.0,  0.0,  1.0,  1.0,    // blue
  ];
 //颜色缓冲区
  const colorBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

  return {
    position: positionBuffer,
    color: colorBuffer,
  };
}
复制代码

而后,在绘图的时候,经过:

gl.bindBuffer();
gl.vertexAttribPointer();
gl.enableVertexAttribArray()

复制代码

来分别使用缓冲区,除了缓冲区外,咱们还须要在顶点着色器和片元着色器中定义全局变量,来接受从缓冲区的传递过来的值。这里先省略,后期在详细介绍缓冲区和着色器的时候会提到.

最后给出绘制出来的图像:

Lark20191204-162205

源码的地址为: github.com/fortheallli…

    最后补充一下,在第二张的画一个点的例子中,咱们机会没有引入任何插件,实际上虽然webgl是浏览器内置的不须要引入,可是为了方便矩阵操做等,也有一些比较实用的工具

相关文章
相关标签/搜索