webGL入门知识讲解

一、webGL简介

什么是webGL

webgl是一种3D绘图协议,衍生于 OpenGL ES2.0,可以结合 Html5 和 JavaScript 在网页上绘制和渲染二/三维图形。
WebGL api 提供三维绘图的方式
图形的绘制主要通过 WebGLRenderingContext 接口完成

WebGL的优势

内嵌在浏览器中,不需要安装任何插件即可运⾏;
只需要⼀个⽂本编辑器和浏览器,就可以编写三维图形程序;
学习和使用比较简单

webgl开源框架

1.Three.js:JavaScript 3D WebGL库
2.Babylon.js:Web3D图形引擎
3.KickJS:Web的开源图形和游戏引擎
4.ClayGL:构建可扩展的Web3D应⽤程序
5.PlayCanvas:网络游戏和3D图形引擎
6.WebGLStudio.js和Litescene.js:开源Web 3D图形编辑器和创建器
7.Luma:Uber的3D WebGL可视化库
8.A-Frame是用于构建VR(虚拟现实)体验的Web框架

二、webGL入门知识

2.1 清空绘图区颜色

  • gl.clearColor(r,g,b,a) :指定清空绘图区的颜⾊,接收四个参数(取值区间为 0.0~1.0)
  • gl.clear(gl.COLOR_BUFFER_BIT) :使用之前指定的颜色,清空绘图区
  • gl.clear 需要和 gl.clearColor 提到的函数搭配使用
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')
  // 指定将要用来清空绘图区的颜色  清空颜色缓存
  // gl.clearColor(r,g,b,a) 指定清空 <canvas> 的颜⾊,接收四个参数(取值区间为 0.0~1.0)
  gl.clearColor(1.0,0.0,0.0,1.0) // red 1.0  green 0.0  blue 0.0 alpha 1.0
  // 使用之前指定的颜色,清空绘图区
  gl.clear(gl.COLOR_BUFFER_BIT)

</script>

2.2 webGL三维坐标

坐标系概览

在这里插入图片描述

绘图区域

在这里插入图片描述

2.3 学习使用attribute变量

attribute 变量只能在顶点着色器中使用,不能在片元着色器中使用
变量声明方法如下:
在这里插入图片描述

获取attribute变量

在这里插入图片描述

给attribute变量赋值

在这里插入图片描述
在这里插入图片描述

改变顶点位置案例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
</head>
<body>
<canvas id="canvas" width="400" height="400">
  此浏览器不支持canvas
</canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    // 只传递顶点数据
    attribute vec4 aPosition;
    void main() {
      gl_Position = aPosition; // vec4(0.0,0.0,0.0,1.0)
      gl_PointSize = 30.0;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');

  // gl.vertexAttrib4f(aPosition, 0.5,0.5,0.0,1.0)
  // gl.vertexAttrib3f(aPosition, 0.5,0.5,0.0)
  // gl.vertexAttrib2f(aPosition, 0.5,0.5)

  let x = 0;
  setInterval(() => {
      
      
    x += 0.1;
    if (x > 1.0) {
      
      
      x = 0;
    }
    // 只改变x值
    gl.vertexAttrib1f(aPosition, x)

    gl.drawArrays(gl.POINTS, 0, 1);
  }, 200)
function initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE) {
      
      
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

  gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE) // 指定顶点着色器的源码
  gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE) // 指定片元着色器的源码

  // 编译着色器
  gl.compileShader(vertexShader)
  gl.compileShader(fragmentShader)

  // 创建一个程序对象
  const program = gl.createProgram();

  gl.attachShader(program, vertexShader)
  gl.attachShader(program, fragmentShader)

  gl.linkProgram(program)

  gl.useProgram(program)

  return program;
}
</script>
流程

在这里插入图片描述

2.4 学习使用uniform

使用 uniform 变量

添加 uniform 变量,设置到颜色上

获取 uniform 变量存储地址

在这里插入图片描述

给uniform 变量赋值

在这里插入图片描述

设置精度

在这里插入图片描述

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    uniform vec4 uPosition;
    // 只传递顶点数据
    attribute vec4 aPosition;
    void main() {
      gl_Position = aPosition; // vec4(0.0,0.0,0.0,1.0)
      gl_PointSize = 10.0;
    }
  `; // 顶点着色器
  // 顶点着色器需要指定精度,如下指定精度为中级精度
  const FRAGMENT_SHADER_SOURCE = `
    precision mediump float;
    uniform vec2 uColor;
    void main() {
      gl_FragColor = vec4(uColor.r, uColor.g, 0.0,1.0); // vec4
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');

  const uColor = gl.getUniformLocation(program, 'uColor')

  const points = []
  ctx.onclick = function(ev) {
      
      
    // 坐标
    const x = ev.clientX
    const y = ev.clientY

    const domPosition = ev.target.getBoundingClientRect();

    const domx = x - domPosition.left
    const domy = y - domPosition.top;

   // 当前画布宽度的一半
    const halfWidth = ctx.offsetWidth / 2
   // 当前画布高度的一半
    const halfHeight = ctx.offsetHeight / 2

    const clickX = (domx - halfWidth) / halfWidth
    const clickY = (halfHeight - domy) / halfHeight

    points.push({
      
      
      clickX, clickY
    })

    for (let i = 0; i < points.length; i++) {
      
      
      gl.vertexAttrib2f(aPosition, points[i].clickX, points[i].clickY)

      gl.uniform2f(uColor, points[i].clickX, points[i].clickY)
      gl.drawArrays(gl.POINTS, 0, 1);
    }
  }
</script>

在这里插入图片描述

流程

在这里插入图片描述

三、图形绘制与变换

3.1绘制多个点

3.1.1什么是缓冲区对象

缓冲区对象是WebGL系统中的一块内存区域,可以一次性地向缓冲区对象中填充大量的顶点数据,然后将这些数据保存在其中,供顶点着色器使用。

3.1.2创建顶点数据

在这里插入图片描述

3.1.3 类型化数组

在这里插入图片描述
在这里插入图片描述

3.1.4创建缓冲区对象

在这里插入图片描述

3.1.5 gl.bindBuffer(target, buffer)

buffer: 已经创建好的缓冲区对象
target:可以是如下两种
gl.ARRAY_BUFFER: 表示缓冲区存储的是顶点的数据
gl.ELEMENT_ARRAY_BUFFER: 表示缓冲区存储的是顶点的索引值

3.1.6 gl.bufferData(target, data, type)

target: 类型同 gl.bindBuffer 中的 target
data: 写⼊缓冲区的顶点数据,如程序中的 points
type: 表示如何使⽤缓冲区对象中的数据,分为以下⼏类
在这里插入图片描述

3.1.7 gl,vertexAttribPointer(location, size, type, normalized, stride, offset) 将缓冲区对象分配给一个attribute变量

location: attribute 变量的存储位置
size: 指定每个顶点所使⽤数据的个数
type: 指定数据格式
normalized: 表示是否将数据归⼀化到 [0, 1] [-1, 1] 这个区间
stride:两个相邻顶点之间的字节数
offset:数据偏移量

3.1.8 gl.enableVertexAttribArray(location) 开启attribute变量
3.1.9 绘制多点案例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    // 只传递顶点数据
    attribute vec4 aPosition;
    void main() {
      gl_Position = aPosition; // vec4(0.0,0.0,0.0,1.0)
      gl_PointSize = 10.0;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');

  const points = new Float32Array([
    -0.5, -0.5,
     0.5, -0.5,
     0.0,  0.5,
  ])
  // 创建缓冲区对象
  const buffer = gl.createBuffer();
  // gl.ARRAY_BUFFER 缓冲区存储的是顶点数据
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  // 将数据写入缓冲区对象
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);// 写入一次,多次绘制
  // 将缓冲区对象分配给一个attribute变量
  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
  // 开启attribute变量
  gl.enableVertexAttribArray(aPosition)
  // gl.vertexAttrib2f(aPosition, 0.0, 0.0)
  // 绘制什么图形,从哪个顶点开始绘制,需要绘制几个顶点
  gl.drawArrays(gl.POINTS, 0, 3);
</script>
3.1.10 缓冲区使用流程

在这里插入图片描述

3.1.11 缓冲区执行过程

在这里插入图片描述

3.2 数据偏移

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
  此浏览器不支持canvas
</canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    attribute float aPointSize;
    void main() {
      gl_Position = aPosition;
      gl_PointSize = aPointSize;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const aPointSize = gl.getAttribLocation(program, 'aPointSize');

  const points = new Float32Array([
    -0.5, -0.5, 10.0, // 10.0
    0.5, -0.5, 20.0, // 20.0
    0.0,  0.5, 30.0, // 30.0
  ])

  const buffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  const BYTES = points.BYTES_PER_ELEMENT;
// 两个数据之间的字节数是3。偏移0个字节取值。
  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, BYTES * 3, 0);

  gl.enableVertexAttribArray(aPosition)
// 两个数据之间的字节数是3。偏移2个字节取值。
  gl.vertexAttribPointer(aPointSize, 1, gl.FLOAT, false, BYTES * 3, BYTES * 2);

  gl.enableVertexAttribArray(aPointSize)

  gl.drawArrays(gl.POINTS, 0, 3);
</script>

3.3 多图形绘制

gl.drawArrays(mode, first, count)的mode参数其实十分强大,可以按照不同的规则绘制不同的图形,可直接绘制的图形有七种,这七种图形是绘制其它各种复杂图形的基础。
在这里插入图片描述

3.4 图形平移

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    attribute float aTranslate;
    void main() {
      gl_Position = vec4(aPosition.x + aTranslate, aPosition.y, aPosition.z, 1.0);
      gl_PointSize = 10.0;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const aTranslate = gl.getAttribLocation(program, 'aTranslate');

  const points = new Float32Array([
    -0.5, -0.5,
     0.5, -0.5,
     0.0,  0.5,
  ])

  const buffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPosition)

  let x = -1;
  setInterval(() => {
      
      
    x += 0.01;
    if (x > 1) {
      
      
      x = -1;
    }
    gl.vertexAttrib1f(aTranslate, x);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
  }, 60)
</script>

3.5 图形缩放

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    attribute float aScale;
    void main() {
      gl_Position = vec4(aPosition.x * aScale, aPosition.y * aScale, aPosition.z * aScale, 1.0);
      gl_PointSize = 10.0;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const aScale = gl.getAttribLocation(program, 'aScale');

  const points = new Float32Array([
    -0.5, -0.5,
     0.5, -0.5,
     0.0,  0.5,
  ])

  const buffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPosition)

  let x = 1;
  setInterval(() => {
      
      
    x += 0.1;
    if (x > 2) {
      
      
      x = 1;
    }
    gl.vertexAttrib1f(aScale, x);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
  }, 60)
</script>

3.6 图形平移-平移矩阵

// 平移矩阵
function getTranslateMatrix(x = 0,y = 0,z = 0) {
  return new Float32Array([
    1.0,0.0,0.0,0.0,
    0.0,1.0,0.0,0.0,
    0.0,0.0,1.0,0.0,
    x  ,y  ,z  , 1,
  ])
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
      gl_PointSize = 10.0;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const mat = gl.getUniformLocation(program, 'mat');

  const points = new Float32Array([
    -0.5, -0.5,
     0.5, -0.5,
     0.0,  0.5,
  ])

  const buffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPosition)

  let x = -1;
  function animation() {
      
      
    x += 0.01;
    if (x > 1) {
      
      
      x = -1;
    }
    
    // getTranslateMatrix的x和y参数是x轴和y轴的偏移量
    const matrix = getTranslateMatrix(x,x);
    // gl.vertexAttrib1f(aTranslate, x);
    gl.uniformMatrix4fv(mat, false, matrix);
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    requestAnimationFrame(animation);
  }

  animation()
</script>

平移矩阵函数推导过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.7缩放矩阵-图形缩放

// 缩放矩阵
function getScaleMatrix(x = 1,y = 1,z = 1) {
  return new Float32Array([
    x  ,0.0,0.0,0.0,
    0.0,y  ,0.0,0.0,
    0.0,0.0,z  ,0.0,
    0.0,0.0,0.0, 1,
  ])
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>
// 矩阵在数学中是按行,在webgl中是按列的,所以把数学中的矩阵沿着对角线做翻转
  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  // uniform对所有变量生效
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
      gl_PointSize = 10.0;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const mat = gl.getUniformLocation(program, 'mat');

  const points = new Float32Array([
    -0.5, -0.5,
     0.5, -0.5,
     0.0,  0.5,
  ])

  const buffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPosition)

  let x = 0.1;
  function animation() {
      
      
    x += 0.01;
    if (x > 1.5) {
      
      
      x = 0.1;
    }
    // getScaleMatrix 的参数 x,y是x轴坐标和y轴坐标分别放大多少倍数;
    const matrix = getScaleMatrix(x,x);
    // gl.vertexAttrib1f(aTranslate, x);
    gl.uniformMatrix4fv(mat, false, matrix);
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    requestAnimationFrame(animation);
  }

  animation()
</script>

缩放矩阵推导过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.8 旋转矩阵

// 绕z轴旋转的旋转矩阵
function getRotateMatrix(deg) {
  return new Float32Array([
    Math.cos(deg)  ,Math.sin(deg) ,0.0,0.0,
    -Math.sin(deg)  ,Math.cos(deg) ,0.0,0.0,
    0.0,            0.0,            1.0,0.0,
    0.0,            0.0,            0.0, 1,
  ])
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>
// 矩阵在数学中是按行,在webgl中是按列的,所以把数学中的矩阵沿着对角线做翻转
  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  // uniform对所有变量生效
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
      gl_PointSize = 10.0;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const mat = gl.getUniformLocation(program, 'mat');

  const points = new Float32Array([
    -0.5, -0.5,
     0.5, -0.5,
     0.0,  0.5,
  ])

  const buffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPosition)

  let x = 0.1;
  function animation() {
      
      
    x += 0.01;
    if (x > 1.5) {
      
      
      x = 0.1;
    }
    // getScaleMatrix 的参数 x,y是x轴坐标和y轴坐标分别放大多少倍数;
    const matrix = getScaleMatrix(x,x);
    // gl.vertexAttrib1f(aTranslate, x);
    gl.uniformMatrix4fv(mat, false, matrix);
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    requestAnimationFrame(animation);
  }

  animation()
</script>

旋转矩阵推导过程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.9 复合图形变换-矩阵组合

// 矩阵复合函数
function mixMatrix(A, B) {
  const result = new Float32Array(16);

  for (let i = 0; i < 4; i++) {
    result[i] = A[i] * B[0] + A[i + 4] * B[1] + A[i + 8] * B[2] + A[i + 12] * B[3]
    result[i + 4] = A[i] * B[4] + A[i + 4] * B[5] + A[i + 8] * B[6] + A[i + 12] * B[7]
    result[i + 8] = A[i] * B[8] + A[i + 4] * B[9] + A[i + 8] * B[10] + A[i + 12] * B[11]
    result[i + 12] = A[i] * B[12] + A[i + 4] * B[13] + A[i + 8] * B[14] + A[i + 12] * B[15]
  }

  return result;
}

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
  此浏览器不支持canvas
</canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const mat = gl.getUniformLocation(program, 'mat');

  const points = new Float32Array([
    -0.5, -0.5,
    0.5, -0.5,
    0.0,  0.5,
  ])

  const buffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPosition)

  let deg = 0;
  let translateX = -1;
  let scaleX = 0.1;
  function animation() {
      
      
    deg += 0.01;
    translateX += 0.01;
    scaleX += 0.01;

    if (translateX > 1) {
      
      
      translateX = -1;
    }

    if (scaleX > 1.5) {
      
      
      scaleX = 0.1;
    }

    const translate = getTranslateMatrix(translateX);
    const scale = getScaleMatrix(scaleX);
    const rotate = getRotateMatrix(deg);

    const matrix = mixMatrix(mixMatrix(translate, scale), rotate)
    // gl.vertexAttrib1f(aTranslate, x);
    gl.uniformMatrix4fv(mat, false, matrix);
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    requestAnimationFrame(animation);
  }

  animation()
</script>

复合图形变换函数推导

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_57307213/article/details/131272889