Introductory knowledge of webGL

1. Introduction to webGL

What is webGL

webgl is a 3D drawing protocol, derived from OpenGL ES2.0, which can draw and render two/three-dimensional graphics on web pages in combination with Html5 and JavaScript.
WebGL api provides 3D drawing.
The drawing of graphics is mainly done through the WebGLRenderingContext interface.

Advantages of WebGL

Embedded in the browser, it can run without installing any plug-ins; it
only needs a text editor and a browser to write 3D graphics programs;
it is relatively easy to learn and use

webgl open source framework

1.Three.js: JavaScript 3D WebGL library
2.Babylon.js: Web3D graphics engine
3.KickJS: Open source graphics and game engine for the Web
4.ClayGL: Build scalable Web3D applications
5.PlayCanvas: Online games and 3D Graphics Engine
6.WebGLStudio.js and Litescene.js: Open Source Web 3D Graphics Editor and Creator
7.Luma: Uber’s 3D WebGL Visualization Library
8.A-Frame is a Web Framework for Building VR (Virtual Reality) Experiences

2. Introductory knowledge of webGL

2.1 Clear the color of the drawing area

  • gl.clearColor(r,g,b,a) : Specifies the color for clearing the drawing area, receiving four parameters (the value range is 0.0~1.0)
  • gl.clear(gl.COLOR_BUFFER_BIT) : Use the previously specified color to clear the drawing area
  • gl.clear needs to be used with the functions mentioned in 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 three-dimensional coordinates

Coordinate Systems Overview

insert image description here

drawing area

insert image description here

2.3 Learning to use attribute variables

The attribute variable can only be used in the vertex shader, not in the fragment shader. The
variable declaration method is as follows:
insert image description here

get attribute variable

insert image description here

Assign values ​​to attribute variables

insert image description here
insert image description here

Changing Vertex Position Case
<!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>
process

insert image description here

2.4 Learning to use uniforms

Use uniform variables

Add a uniform variable and set it to the color

Get uniform variable storage address

insert image description here

Assign values ​​to uniform variables

insert image description here

set precision

insert image description here

insert image description here

<!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>

insert image description here

process

insert image description here

3. Graphic drawing and transformation

3.1 Drawing multiple points

3.1.1 What is a buffer object

The buffer object is a memory area in the WebGL system. You can fill a large amount of vertex data into the buffer object at one time, and then save the data in it for use by the vertex shader.

3.1.2 Create vertex data

insert image description here

3.1.3 Typed arrays

insert image description here
insert image description here

3.1.4 Create a buffer object

insert image description here

3.1.5 gl.bindBuffer(target, buffer)

buffer: The created buffer object
target: can be the following two
gl.ARRAY_BUFFER: Indicates that the buffer stores the vertex data
gl.ELEMENT_ARRAY_BUFFER: Indicates that the buffer stores the vertex index value

3.1.6 gl.bufferData(target, data, type)

target: same type as target in gl.bindBuffer.
data: vertex data written into the buffer, such as points in the program.
type: indicates how to use the data in the buffer object, divided into the following categories
insert image description here

3.1.7 gl,vertexAttribPointer(location, size, type, normalized, stride, offset) assign the buffer object to an attribute variable

location: the storage location of the attribute variable
size: specifies the number of data used by each vertex
type: specifies the data format
normalized: indicates whether to normalize the data to the interval [0, 1] [-1, 1] stride
: The number of bytes offset between two adjacent vertices
: data offset

3.1.8 gl.enableVertexAttribArray(location) enable attribute variable
3.1.9 Drawing multi-point cases
<!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 Buffer usage process

insert image description here

3.1.11 Buffer execution process

insert image description here

3.2 Data Offset

<!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 Multi-graphic drawing

The mode parameter of gl.drawArrays(mode, first, count) is actually very powerful. Different graphics can be drawn according to different rules. There are seven kinds of graphics that can be drawn directly. These seven kinds of graphics are the basis for drawing other complex graphics.
insert image description here

3.4 Graphics translation

<!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 Graphics scaling

<!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 Graphic translation-translation matrix

// 平移矩阵
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>

Derivation process of translation matrix function

insert image description here
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here

3.7 Scaling Matrix - Graph Scaling

// 缩放矩阵
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>

Scaling matrix derivation process

insert image description here
insert image description here
insert image description here

insert image description here
insert image description here

3.8 Rotation Matrix

// 绕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>

Rotation matrix derivation process

insert image description here

insert image description here

insert image description here
insert image description here
insert image description here
insert image description here

3.9 Composite graphics transformation-matrix combination

// 矩阵复合函数
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>

Derivation of Transformation Function of Composite Graphics

insert image description here

Guess you like

Origin blog.csdn.net/m0_57307213/article/details/131272889