html 与webgl | 青训营笔记

181 阅读6分钟

webgl学习(基础篇)

引子:GPU V.S. CPU

GPU芯片,就是常说的“显卡”,擅长做并行计算;CPU则长于横向计算。两者组成异构计算的一对黄金搭档。

计算领域正初步形成“专用”和“通用”的格局。随着人工智能产业爆炸式增长,导致计算复杂化和算力不足,加上CPU并行计算能力不及GPU,使得GPU的通用性计算优势愈发明显,在一众xPU中脱颖而出,成为算力时代VIP。

WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染(部分计算GPU) ,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。总结一下,WebGL的本质 —— JavaScript操作OpenGL接口

下面是WEBGL最简单的一个示例程序,它会在画布上绘制一个绿色的三角形:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>WebGL Example</title>
    <style>
      canvas {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <canvas id="glCanvas" width="640" height="480"></canvas>
    <script>
      // 获取画布对象
      const canvas = document.getElementById("glCanvas");

      // 获取WebGL渲染上下文
      const gl = canvas.getContext("webgl");

      // 定义顶点数据
      const vertices = [
        0.0, 0.5, 0.0,
        -0.5, -0.5, 0.0,
        0.5, -0.5, 0.0
      ];

      // 创建顶点缓冲区
      const vertexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

      // 定义着色器代码
      const vertexShaderCode = `
        attribute vec3 position;

        void main() {
          gl_Position = vec4(position, 1.0);
        }
      `;

      const fragmentShaderCode = `
        precision mediump float;
        uniform vec4 color;

        void main() {
          gl_FragColor = color;
        }
      `;

      // 编译着色器
      const vertexShader = gl.createShader(gl.VERTEX_SHADER);
      gl.shaderSource(vertexShader, vertexShaderCode);
      gl.compileShader(vertexShader);

      const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      gl.shaderSource(fragmentShader, fragmentShaderCode);
      gl.compileShader(fragmentShader);

      // 创建着色器程序
      const shaderProgram = gl.createProgram();
      gl.attachShader(shaderProgram, vertexShader);
      gl.attachShader(shaderProgram, fragmentShader);
      gl.linkProgram(shaderProgram);

      // 启用着色器程序
      gl.useProgram(shaderProgram);

      // 设置顶点属性
      const positionAttributeLocation = gl.getAttribLocation(shaderProgram, "position");
      gl.enableVertexAttribArray(positionAttributeLocation);
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
      gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

      // 设置uniform变量
      const colorUniformLocation = gl.getUniformLocation(shaderProgram, "color");
      gl.uniform4fv(colorUniformLocation, [0.0, 1.0, 0.0, 1.0]);

      // 绘制三角形
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT);
      gl.drawArrays(gl.TRIANGLES, 0, 3);
    </script>
  </body>
</html>

在这个示例程序中,我们首先获取了画布对象,并通过getContext方法获取了WebGL渲染上下文。然后,我们定义了一个包含三个顶点坐标的数组,创建了一个顶点缓冲区,并把顶点数据绑定到缓冲区中。

接下来,我们定义了两个着色器代码:一个顶点着色器和一个片段着色器。顶点着色器的作用是把顶点坐标转换成屏幕坐标,片段着色器的作用是给每个片段(即像素)着色。然后,我们创建了顶点着色器和片段着色器,并将它们编译成可执行的着色器程序。

接下来,我们设置顶点属性和uniform变量。顶点属性是顶点数据中的属性,比如顶点的坐标、颜色等。我们把顶点坐标属性绑定到顶点缓冲区中,并启用该属性。uniform变量是全局变量,可以在着色器程序中被访问,但它们的值是由JavaScript代码设置的。在这个示例程序中,我们设置了一个表示颜色的uniform变量。

最后,我们清空画布,并使用drawArrays方法绘制三角形。drawArrays方法指定了要绘制的基本几何图形的类型和顶点数量。在这个示例程序中,我们使用gl.TRIANGLES类型绘制三角形,顶点数量为3。

总的来说,这个示例程序演示了WEBGL的基本流程:定义顶点数据、创建着色器、设置属性和uniform变量、绘制图形。WEBGL中的每个绘制操作都需要执行这些步骤,所以对于复杂的WEBGL应用程序来说,这些步骤通常会被封装到一个渲染引擎中。

着色器(Shader)编写

在WebGL中,着色器(shader)是一种用于渲染图形的计算机程序,它们运行在GPU上,通常由两个部分组成:顶点着色器和片段着色器。顶点着色器用于将三维模型的顶点坐标转换为屏幕上的二维坐标,片段着色器用于给每个像素着色,形成最终的图像。

在编写WebGL应用程序时,着色器是非常重要的组成部分。以下是一些需要注意的地方:

  1. 着色器代码必须是GLSL(OpenGL Shading Language)语言的。GLSL是一种C语言的子集,它专门用于编写图形渲染着色器。GLSL具有自己的语法、数据类型和函数库。

  2. 顶点着色器和片段着色器必须配合使用。顶点着色器用于处理顶点坐标和顶点属性,而片段着色器用于为每个像素计算颜色。两个着色器都必须编译并链接为一个可执行的着色器程序才能使用。

  3. 在编写着色器代码时,需要遵循一些硬件限制。例如,GPU有硬件限制,对于一些操作的执行速度有限制,比如顶点着色器中使用的纹理采样器数量、片段着色器中使用的循环数量等等。

  4. 在使用着色器时,需要将顶点数据和着色器程序连接起来。连接过程中,需要指定顶点属性和uniform变量的类型和位置等信息。

  5. 着色器代码中有一些内置的变量和函数,比如顶点着色器中的gl_Position和片段着色器中的gl_FragColor等。这些变量和函数用于指定顶点和像素的位置、颜色等信息。

总之,着色器是WebGL中非常重要的组成部分,需要认真编写和使用。需要熟悉GLSL语言,理解硬件限制,并能够将顶点数据和着色器程序正确地连接起来。

推荐一个网站shadertoy,可以看到很多有趣的着色器。

数据类型

GLSL ES 是一种强类型的编程语言

矢量
  • vec4 表示由4个浮点数组成的矢量,可以使用 vec4(v0, v1, v2, v3) 进行创建。

  • float 表示浮点数

矩阵
  • 矩阵构造:传入值是列主序的(写成列向量的形式
访问矢量中的元素
vec3 v3 =vec3(1.0,2.0,3.0);
float f;
f=v3.x;//访问第一个元素
f=v3.y;//访问第二个元素
f=v3.z;//访问第三个元素
//混合访问
vec2 v2;
v2=v3.xy;
访问矩阵中的元素
mat 4 =mat4(……)
vec4 v4 =m4[0];//访问第一列元素
float m23=m4[1][2];//访问某个元素
矩阵和浮点数的运算
取样器

sample2DsamplerCube

只能被定义为全局变量的关键字

const

attribute

表示逐顶点的信息;只能在顶点着色器;

uniform(统一、共享)

通过gl.getUniformLocation变量来获取uniform变量的存储地址

通过gl.uniform4f向uniform变量中赋值

varying

用于在顶点着色器和片元着色器之间传递数据。当我们需要在片元着色器中使用从顶点着色器传递过来的数据时,我们就可以使用varying变量。

顶点着色器参数:

gl_Position:

gl_Pointsize:

片元着色器参数:

gl_FragColor