绘制变换三角形

# 三角形绘制和多边形

缓冲区对象(buffer object) 它可以一次性地向着色器中传入多个顶点的数据。缓冲区对象是webgl系统中一块内存区域,我们可以一次性地向缓冲区对象中填充大量的顶点数据,然后将这些数据保存在其中,供顶点着色器使用。

使用缓冲区对象向顶点着色器传入多个顶点数据,需要遵循五个步骤

  • 创建缓冲区对象(gl.createBuffer)
  • 绑定缓冲区对象(gl.bindBuffer) 绑定到webgl已经存在的目标上,这个目标表示缓冲区对象的用途,这样webgl才能正确处理其中的内容。
  • 将数据写入缓冲区对象(gl.bufferData)
  • 将缓冲区对象分配给一个attribute变量(gl.vertexAttribPointer)
  • 开启attribute变量(gl.enableVertexAttribArray),使分配到attribute变量真生生效,顶点着色器可以访问缓冲区中的数据。

提示

gl.deleteBuffer(buffer)删除缓冲区对象 gl.disableVertexAttribArray()关闭缓冲区分配

提示

为了绘制三维图形,webgl通常需要同时处理大量相同类型的数据,为了优化性能,webgl为每种基本数据类型引入了一种特殊的数组(类型化数组),浏览器事先知道数组中的数据类型,所以处理起来也更加有效率。

提示

gl.vertexAttribPointer(location,size,type,normalized,stride,offset)

使用缓冲区对象向顶点着色器传输多个顶点数据的五个步骤
顶点着色器执行过程中缓冲区数据的传输过程

例子一:使用缓冲区对象中的数据绘制三个点

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用缓冲区对象绘制多点</title>
    <script src="./lib/cuon-matrix.js"></script>
    <script src="./lib/cuon-utils.js"></script>
    <script src="./lib/webgl-debug.js"></script>
    <script src="./lib/webgl-utils.js"></script>
</head>

<body onload="main()">
    <canvas width="400" height="400" id="mulitiPoint"></canvas>
   <script>
      let VSHADER_SOURCE =
          `attribute vec4 a_Position;
           void main(){
              gl_Position=a_Position;
              gl_PointSize=10.0; //该句只有在绘制单个点的时候才起作用
           }`;

      let FSHADER_SOURCE =
          `void main(){
              gl_FragColor=vec4(1.0,0.0,0.0,1.0);
           }`;

      function main() {
          let canvas = document.querySelector('#mulitiPoint');
          let gl = getWebGLContext(canvas);
          if (!gl) {
              console.info('failed to initalize gl.');
              return;
          }

          if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.info('failed to initalize shaders.');
              return;
          }

          let n = initVertextBuffers(gl);
          if (n < 0) {
              console.info('failed to set the position of the vertices');
              return;
          }

          gl.clearColor(1.0, 1.0, 0.0, 1.0);
          gl.clear(gl.COLOR_BUFFER_BIT);
          gl.drawArrays(gl.POINTS, 0, n);//绘制3个点
          //gl.drawArrays(gl.LINE_STRIP, 0, n);//绘制两条线
          //gl.drawArrays(gl.LINES, 0, n);//绘制线段
          //gl.drawArrays(gl.LINE_LOOP, 0, n); //绘制空心三角形
          //gl.drawArrays(gl.TRIANGLES, 0, n); //绘制实心三角形
          //gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); //绘制实心三角形
          //gl.drawArrays(gl.TRIANGLE_FAN, 0, n); //绘制实心三角形
      }

      function initVertextBuffers(gl) {
          let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
          let n = 3;
          let vertexBuffer = gl.createBuffer();
          if (!vertexBuffer) {
              console.info('failed to create the buffer object');
              return -1;
          }
          //将缓冲区对象绑定到目标
          gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
          //向缓冲区写入数据
          gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
          let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
          //将缓冲区对象分配给a_Position
          gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
          //连接a_Position变量与分配给他的缓冲区对象
          gl.enableVertexAttribArray(a_Position);
          return n;
      }
  </script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
gl.drawArrays(gl.POINTS, 0, n)绘制三个点
gl.drawArrays(gl.LINE_STRIP, 0, n)绘制两条线
gl.drawArrays(gl.LINES, 0, n)绘制一条线段
gl.drawArrays(gl.LINE_LOOP, 0, n)绘制空心三角形
gl.drawArrays(gl.TRIANGLES, 0, n)绘制实心三角形
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n)绘制实心三角形
gl.drawArrays(gl.TRIANGLE_FAN, 0, n)绘制实心三角形
基本的绘图图形说明
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>绘制多边形</title>
    <script src="../lib/webgl-utils.js"></script>
    <script src="../lib/webgl-debug.js"></script>
    <script src="../lib/cuon-utils.js"></script>
    <script src="../lib/cuon-matrix.js"></script>
</head>

<body onload="main()">
    <canvas width="400" height="400" id='Rect'>
        请使用支持的浏览器来实现
    </canvas>
    <script>
        let VSHADER_SOURCE =
            `attribute vec4 a_Position;
             void main(){
                gl_Position=a_Position;
            }`;
        let FSHADER_SOURCE =
            `void main(){
                gl_FragColor=vec4(1.0,0.0,0.0,1.0);
            }`;

        function main() {
            let canavas = document.querySelector('#Rect');
            let gl = getWebGLContext(canavas);
            if (!gl) {
                console.info('failed initalized gl.');
                return;
            }

            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
                console.info('failed initalized shaders.');
                return;
            }

            let n = initVertexBuffer(gl);
            if (n < 0) {
                console.info('failed initalized vertexBuffer.');
                return;
            }

            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.drawArrays(gl.TRIANGLE_FAN, 0, n);
        }

        function initVertexBuffer(gl) {
            let vertices = new Float32Array([-0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5]);
            let n = 4;
            let vertexBuffer = gl.createBuffer();
            if (!vertexBuffer) {
                console.info('failed initaized vertexBuffer.');
                return -1;
            }
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STREAM_DRAW);
            let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
            gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
            gl.enableVertexAttribArray(a_Position);
            return n;
        }
    </script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
绘制多边形

# 变换

  • 平移

    x'=x+Tx

    y'=y+Ty

    z'=z+Tz

    (x,y,z) 偏移了 (Tx,Ty,Tz) 后到达点 (x',y',z')

    平移计算

    例子二:三角形平移

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>绘制三角形并且移动</title>
        <script src="./lib/cuon-matrix.js"></script>
        <script src="./lib/cuon-utils.js"></script>
        <script src="./lib/webgl-debug.js"></script>
        <script src="./lib/webgl-utils.js"></script>
    </head>
    
    <body onload="main();">
        <canvas width="300" height="300" id="translate">
            请使用支持的浏览器查看
        </canvas>
        <script>
            let VSHADER_SOURCE =
                `attribute vec4 a_Position;
                 uniform vec4 u_Translation;
                 void main(){
                    gl_Position=a_Position+u_Translation;
                 }`;
    
            let FSHADER_SOURCE =
                `void main(){
                    gl_FragColor=vec4(1.0,0.5,0.5,1.0);
                }`;
    
            let Tx = 0.5,
                Ty = 0.5,
                Tz = 0.0;
    
            function main() {
                let canvas = document.querySelector('#translate');
                let gl = getWebGLContext(canvas);
                if (!gl) {
                    console.info('failed initalizead gl.');
                    return;
                }
    
                if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
                    console.info('failed initaized shaders.');
                    return;
                }
    
                let n = initVertexBuffer(gl);
                if (n < 0) {
                    console.info('failed initalized buffer');
                    return;
                }
                let u_Translation = gl.getUniformLocation(gl.program, 'u_Translation');
                gl.uniform4f(u_Translation, Tx, Ty, Tz, 0.0);
                gl.clearColor(0.0, 1.0, 0.0, 1.0);
                gl.clear(gl.COLOR_BUFFER_BIT);
                gl.drawArrays(gl.TRIANGLES, 0, n);
            }
    
            function initVertexBuffer(gl) {
                let vertices = new Float32Array([0.0, 0.5, -0.5, 0.0, 0.5, 0.0]);
                let n = 3;
                let vertexBuffer = gl.createBuffer();
                if (!vertexBuffer) {
                    console.info('failed initalize vertexBuffer.');
                    return -1;
                }
                gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
                gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
                let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
                gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
                gl.enableVertexAttribArray(a_Position);
                return n;
            }
        </script>
    </body>
    </html>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    三角形平移
  • 旋转

    • 描述旋转必须指明:旋转轴(图形将围绕旋转轴旋转)
    • 旋转方向(顺时针旋转还是逆时针旋转)
    • 旋转角度(图形旋转经过的角度)

    提示

    正旋转,观测者在Z轴正半轴某处,视线沿着Z轴负方向进行观察,那么看到的物体就是逆时针旋转的。遵循右手法则旋转。WebGL默认是右手旋转。

    提示

    sin(a+b) = sinacosb - cosasinb

    sin(a-b) = sinacosb + cosasinb

    cos(a+b) = cosacosb - sinasinb

    cos(a-b) = cosacosb + sinasinb

    例子三:三角形正旋转90度

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>三角形旋转</title>
        <script src="./lib/webgl-utils.js"></script>
        <script src="./lib/webgl-debug.js"></script>
        <script src="./lib/cuon-utils.js"></script>
        <script src="./lib/cuon-matrix.js"></script>
    </head>
    
    <body onload="main();">
        <canvas width="300" height="300" id="webgl">
            请使用支持的浏览器查看这个效果
        </canvas>
        <script>
            let VSHADER_SOURCE =
                `attribute vec4 a_Position;
                uniform float u_CosB,u_SinB;
                void main(){
                    gl_Position.x=a_Position.x*u_CosB-a_Position.y*u_SinB;
                    gl_Position.y=a_Position.x*u_SinB+a_Position.y*u_CosB;
                    gl_Position.z=a_Position.z;
                    gl_Position.w=1.0;
                }`;
            let FSHADER_SOURCE =
                `void main(){
                    gl_FragColor=vec4(1.0,0.0,0.0,1.0);
                }`;
    
            let angle = 90.0;
            function main() {
                let canvas = document.querySelector('#webgl');
                let gl = getWebGLContext(canvas);
                if (!gl) {
                    console.info('failed initalized gl.');
                    return;
                }
    
                if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
                    console.info('failed initalized shaders.');
                    return;
                }
    
                let n = initVertexBuffer(gl);
                if (n < 0) {
                    console.info('failed initalized vertexBuffer.');
                    return;
                }
    
                let radian = Math.PI * angle / 180.0;
                let cosB = Math.cos(radian);
                let sinB = Math.sin(radian);
    
                let u_CosB = gl.getUniformLocation(gl.program, 'u_CosB');
                let u_SinB = gl.getUniformLocation(gl.program, 'u_SinB');
    
                gl.uniform1f(u_CosB, cosB);
                gl.uniform1f(u_SinB, sinB);
    
                gl.clearColor(0.0, 0.0, 0.0, 1.0);
                gl.clear(gl.COLOR_BUFFER_BIT);
                gl.drawArrays(gl.TRIANGLES, 0, n);
            }
    
            function initVertexBuffer(gl) {
                let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
                let n = 3;
                let vertexBuffer = gl.createBuffer();
                if (!vertexBuffer) {
                    console.info('initalize vertexBuffer failed.');
                    return -1;
                }
                gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
                gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
                let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
                if (a_Position < 0) {
                    console.info('initalized position failed.');
                    return -1;
                }
                gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
                gl.enableVertexAttribArray(a_Position);
                return n;
            }
        </script>
    </body>
    </html>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    三角形正旋转90度

    注意

    对于简单的变换,可以使用数学表达式来实现。但是当遇到既有旋转又有平移的复杂情况时,数学表达式书写就变得比较繁琐。解决办法是用变换矩阵来代替数学表达式。

  • 缩放

例子四:使用矩阵实现平移、旋转和缩放

  <!DOCTYPE html>
  <html lang="en">

  <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>使用矩阵实现平移、旋转、缩放</title>
      <script src="./lib/cuon-matrix.js"></script>
      <script src="./lib/cuon-utils.js"></script>
      <script src="./lib/webgl-debug.js"></script>
      <script src="./lib/webgl-utils.js"></script>
  </head>

  <body onload="test()">
      <canvas width="200" height="200" id="webgl">
          请使用支持的浏览器查看
      </canvas>
      <script>
          let VSHADER_SOURCE =
          `attribute vec4 a_Position;
           uniform mat4 u_xformMatrix;
           void main(){
              gl_Position=u_xformMatrix*a_Position;
           }`;
          let FSHADER_SOURCE =
          `void main(){
              gl_FragColor=vec4(1.0,0.0,0.0,1.0);
          }`;

          let ANGLE = 90;
          let Tx = 0.5;
          let Ty = 0.5;
          let Tz = 0.0;
          let Sx = 1.0;
          let Sy = 1.5;
          let Sz = 1.0;

          function test(){
              let canvas = document.querySelector('#webgl');
              let gl = getWebGLContext(canvas);
              if (!gl) {
                  console.info('failed initalized gl.');
                  return;
              }

              if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
                  console.info('failed initalized shaders.');
                  return;
              }

              let n = initVertexBuffer(gl);
              if (n < 0) {
                  console.info('failed initalized vertexBuffer.');
                  return;
              }

              let radian = Math.PI * ANGLE / 180.0;
              let cosB = Math.cos(radian);
              let sinB = Math.sin(radian);
              //webgl矩阵是列主序的
              let xformMatrix = new Float32Array([
                  cosB, sinB, 0.0, 0.0,
                  -sinB, cosB, 0.0, 0.0,
                  0.0, 0.0, 1.0, 0.0,
                  0.0, 0.0, 0.0, 1.0
              ]);

              let xformMatrix1 = 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,
                  Tx, Ty, Tz, 1.0
              ]);

              let xformMatrix2 = new Float32Array([
                  Sx, 0.0, 0.0, 0.0,
                  0.0, Sy, 0.0, 0.0,
                  0.0, 0.0, Sz, 0.0,
                  0.0, 0.0, 0.0, 1.0
              ]);
            
              let u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
              //给矩阵变量传值
              //gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);
              //gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix1);
              gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix2);

              gl.clearColor(0.0, 0.0, 0.0, 1.0);
              gl.clear(gl.COLOR_BUFFER_BIT);
              gl.drawArrays(gl.TRIANGLES, 0, n);
          }

          function initVertexBuffer(gl) {
              let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
              let n = 3;
              let vertexBuffer = gl.createBuffer();
              if (!vertexBuffer) {
                  console.info('initalize vertexBuffer failed.');
                  return -1;
              }
              gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
              gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
              let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
              if (a_Position < 0) {
                  console.info('initalized position failed.');
                  return -1;
              }
              gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
              gl.enableVertexAttribArray(a_Position);
              return n;
          }
      </script>
  </body>

  </html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

注意

WebGL和OpenGL一样,矩阵元素是按照列主序储存在数组中的。

上次更新: 2025/02/15, 13:42:25
最近更新
01
Git问题集合
01-29
02
安装 Nginx 服务器
01-25
03
安装 Docker 容器
01-25
更多文章>
×
×