5 创建多个缓冲区

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Clear canvas</title>
  6. </head>
  7. <body>
  8. <canvas id="webgl" width="400" height="400">
  9. Please use the browser supporting "canvas"
  10. </canvas>
  11. <script src="../lib/webgl-utils.js"></script>
  12. <script src="../lib/webgl-debug.js"></script>
  13. <script src="../lib/cuon-utils.js"></script>
  14. <script>
  15. /**
  16. * 设置着色器
  17. */
  18. function setShaders(gl) {
  19. // 顶底着色气
  20. var VSHADER_SOURCE =
  21. 'attribute vec4 a_Position;\n' +
  22. 'attribute float a_PointSize;\n' +
  23. 'void main() {\n' +
  24. // vec4(x, y, z, w); x表示横向轴,y表示纵向轴,z轴, w齐次坐标(默认为1)
  25. // w是齐次坐标 齐次坐标(x, y, z, w) 等价于 (x/w, y/w, z/w);
  26. ' gl_Position = a_Position;\n' + // 设置点的位置
  27. ' gl_PointSize = a_PointSize;\n' + // 设置点的大小
  28. '}\n';
  29. // 片元着色气
  30. var FSHADER_SOURCE =
  31. 'precision mediump float;\n' +
  32. 'uniform vec4 u_FragColor;\n' + // uniform变量
  33. 'void main() {\n' +
  34. ' gl_FragColor = u_FragColor;\n' + // 设置颜色,rgba
  35. '}\n';
  36. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  37. throw new TypeError("未能初始化着色器");
  38. }
  39. // gl.getUniformLocation 获取uniform变量的存储位置
  40. var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor')
  41. gl.uniform4f(u_FragColor, 0.0, 1.0, 0.0, 1)
  42. }
  43. function main() {
  44. // 获取 <canvas> 元素
  45. var canvas = document.getElementById('webgl');
  46. // 获取 WebGL 绘图上下文
  47. var gl = getWebGLContext(canvas);
  48. if (!gl) {
  49. console.log('Failed to get the rendering context for WebGL');
  50. return;
  51. }
  52. var initVertexBuffers = function () {
  53. // 1.创建缓冲区对象
  54. var vertexBuffer = gl.createBuffer();
  55. var sizeBuffer = gl.createBuffer();
  56. if (!vertexBuffer || !sizeBuffer) {
  57. throw new TypeError("创建缓冲区失败");
  58. }
  59. var vertices = new Float32Array([
  60. 0.0, 0.5,
  61. -0.5, -0.5,
  62. 0.5, -0.5
  63. ])
  64. var sizes = new Float32Array([10.0, 20.0, 30.0])
  65. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  66. gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  67. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  68. if (a_Position < 0) {
  69. throw new TypeError("无法获取变量的存储位置")
  70. }
  71. gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  72. gl.enableVertexAttribArray(a_Position);
  73. gl.bindBuffer(gl.ARRAY_BUFFER, sizeBuffer);
  74. gl.bufferData(gl.ARRAY_BUFFER, sizes, gl.STATIC_DRAW);
  75. var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
  76. if (a_PointSize < 0) {
  77. throw new TypeError("无法获取变量的存储位置")
  78. }
  79. gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, 0, 0);
  80. gl.enableVertexAttribArray(a_PointSize);
  81. return 3;
  82. }
  83. setShaders(gl);
  84. var n = initVertexBuffers(gl);
  85. // 设置背景颜色
  86. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  87. // 可以查询 gl.COLOR_BUFFER_BIT 的含义,以及clear方法的使用 https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/clear#%E5%8F%A5%E6%B3%95
  88. // gl.COLOR_BUFFER_BIT 颜色缓冲区
  89. // 清空颜色缓冲区
  90. gl.clear(gl.COLOR_BUFFER_BIT);
  91. // gl.drawArrays(mode, first, count);
  92. // mode 表示绘制的方式
  93. // first 从那个顶点开始绘制
  94. // count 绘制几个顶点
  95. gl.drawArrays(gl.POINTS, 0, n);
  96. }
  97. main()
  98. </script>
  99. </body>
  100. </html>

5.1vertexAttribPointer的进步和偏移参数

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Clear canvas</title>
  6. </head>
  7. <body>
  8. <canvas id="webgl" width="400" height="400">
  9. Please use the browser supporting "canvas"
  10. </canvas>
  11. <script src="../lib/webgl-utils.js"></script>
  12. <script src="../lib/webgl-debug.js"></script>
  13. <script src="../lib/cuon-utils.js"></script>
  14. <script>
  15. /**
  16. * 设置着色器
  17. */
  18. function setShaders(gl) {
  19. // 顶底着色气
  20. var VSHADER_SOURCE =
  21. 'attribute vec4 a_Position;\n' +
  22. 'attribute float a_PointSize;\n' +
  23. 'void main() {\n' +
  24. // vec4(x, y, z, w); x表示横向轴,y表示纵向轴,z轴, w齐次坐标(默认为1)
  25. // w是齐次坐标 齐次坐标(x, y, z, w) 等价于 (x/w, y/w, z/w);
  26. ' gl_Position = a_Position;\n' + // 设置点的位置
  27. ' gl_PointSize = a_PointSize;\n' + // 设置点的大小
  28. '}\n';
  29. // 片元着色气
  30. var FSHADER_SOURCE =
  31. 'precision mediump float;\n' +
  32. 'uniform vec4 u_FragColor;\n' + // uniform变量
  33. 'void main() {\n' +
  34. ' gl_FragColor = u_FragColor;\n' + // 设置颜色,rgba
  35. '}\n';
  36. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  37. throw new TypeError("未能初始化着色器");
  38. }
  39. // gl.getUniformLocation 获取uniform变量的存储位置
  40. var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor')
  41. gl.uniform4f(u_FragColor, 0.0, 1.0, 0.0, 1)
  42. }
  43. function main() {
  44. // 获取 <canvas> 元素
  45. var canvas = document.getElementById('webgl');
  46. // 获取 WebGL 绘图上下文
  47. var gl = getWebGLContext(canvas);
  48. if (!gl) {
  49. console.log('Failed to get the rendering context for WebGL');
  50. return;
  51. }
  52. var initVertexBuffers = function () {
  53. // 1.创建缓冲区对象
  54. var vertexBuffer = gl.createBuffer();
  55. if (!vertexBuffer) {
  56. throw new TypeError("创建缓冲区失败");
  57. }
  58. var vertices = new Float32Array([
  59. 0.0, 0.5, 10.0,
  60. -0.5, -0.5, 20.0,
  61. 0.5, -0.5, 30.0
  62. ])
  63. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  64. gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  65. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  66. if (a_Position < 0) {
  67. throw new TypeError("无法获取变量的存储位置")
  68. }
  69. var fsize = vertices.BYTES_PER_ELEMENT;
  70. gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, fsize * 3, 0);
  71. gl.enableVertexAttribArray(a_Position);
  72. var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
  73. if (a_PointSize < 0) {
  74. throw new TypeError("无法获取变量的存储位置")
  75. }
  76. gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, fsize * 3, fsize * 2);
  77. gl.enableVertexAttribArray(a_PointSize);
  78. return 3;
  79. }
  80. setShaders(gl);
  81. var n = initVertexBuffers(gl);
  82. // 设置背景颜色
  83. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  84. // 可以查询 gl.COLOR_BUFFER_BIT 的含义,以及clear方法的使用 https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/clear#%E5%8F%A5%E6%B3%95
  85. // gl.COLOR_BUFFER_BIT 颜色缓冲区
  86. // 清空颜色缓冲区
  87. gl.clear(gl.COLOR_BUFFER_BIT);
  88. // gl.drawArrays(mode, first, count);
  89. // mode 表示绘制的方式
  90. // first 从那个顶点开始绘制
  91. // count 绘制几个顶点
  92. gl.drawArrays(gl.POINTS, 0, n);
  93. }
  94. main()
  95. </script>
  96. </body>
  97. </html>

5.2 修改颜色(varying变量)

一致的 (uniform变量)
可变的变量(varying变量)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Clear canvas</title>
  6. </head>
  7. <body>
  8. <canvas id="webgl" width="400" height="400">
  9. Please use the browser supporting "canvas"
  10. </canvas>
  11. <script src="../lib/webgl-utils.js"></script>
  12. <script src="../lib/webgl-debug.js"></script>
  13. <script src="../lib/cuon-utils.js"></script>
  14. <script>
  15. /**
  16. * 设置着色器
  17. */
  18. function setShaders(gl) {
  19. // 顶底着色气
  20. var VSHADER_SOURCE =
  21. 'attribute vec4 a_Position;\n' +
  22. 'attribute float a_PointSize;\n' +
  23. 'attribute vec4 a_Color;\n' +
  24. 'varying vec4 v_Color;\n' + // varying
  25. 'void main() {\n' +
  26. ' gl_Position = a_Position;\n' + // 设置点的位置
  27. ' gl_PointSize = a_PointSize;\n' +
  28. ' v_Color = a_Color;\n' + // 设置点的大小
  29. '}\n';
  30. // 片元着色气
  31. var FSHADER_SOURCE =
  32. 'precision mediump float;\n' +
  33. 'varying vec4 v_Color;\n' + // varying
  34. 'void main() {\n' +
  35. ' gl_FragColor = v_Color;\n' + // 设置颜色,rgba
  36. '}\n';
  37. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  38. throw new TypeError("未能初始化着色器");
  39. }
  40. // gl.getUniformLocation 获取uniform变量的存储位置
  41. var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor')
  42. gl.uniform4f(u_FragColor, 0.0, 1.0, 0.0, 1)
  43. }
  44. function main() {
  45. // 获取 <canvas> 元素
  46. var canvas = document.getElementById('webgl');
  47. // 获取 WebGL 绘图上下文
  48. var gl = getWebGLContext(canvas);
  49. if (!gl) {
  50. console.log('Failed to get the rendering context for WebGL');
  51. return;
  52. }
  53. var initVertexBuffers = function () {
  54. // 1.创建缓冲区对象
  55. var vertexBuffer = gl.createBuffer();
  56. var sizeBuffer = gl.createBuffer();
  57. if (!vertexBuffer) {
  58. throw new TypeError("创建缓冲区失败");
  59. }
  60. var vertices = new Float32Array([
  61. // 顶点坐标,大小,颜色
  62. 0.0, 0.5, 1.0, 0.0, 0.0,
  63. -0.5, -0.5, 0.0, 1.0, 0.0,
  64. 0.5, -0.5, 0.0, 0.0, 1.0,
  65. ])
  66. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  67. gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  68. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  69. if (a_Position < 0) {
  70. throw new TypeError("无法获取变量的存储位置")
  71. }
  72. var fsize = vertices.BYTES_PER_ELEMENT;
  73. gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, fsize * 5, 0);
  74. gl.enableVertexAttribArray(a_Position);
  75. var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
  76. if (a_Color < 0) {
  77. throw new TypeError("无法获取变量的存储位置")
  78. }
  79. gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, fsize * 5, fsize * 2);
  80. gl.enableVertexAttribArray(a_Color);
  81. var sizes = new Float32Array([10.0, 20.0, 30.0])
  82. gl.bindBuffer(gl.ARRAY_BUFFER, sizeBuffer);
  83. gl.bufferData(gl.ARRAY_BUFFER, sizes, gl.STATIC_DRAW);
  84. var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
  85. if (a_PointSize < 0) {
  86. throw new TypeError("无法获取变量的存储位置")
  87. }
  88. gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, 0, 0);
  89. gl.enableVertexAttribArray(a_PointSize);
  90. return 3;
  91. }
  92. setShaders(gl);
  93. var n = initVertexBuffers(gl);
  94. // 设置背景颜色
  95. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  96. // 可以查询 gl.COLOR_BUFFER_BIT 的含义,以及clear方法的使用 https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/clear#%E5%8F%A5%E6%B3%95
  97. // gl.COLOR_BUFFER_BIT 颜色缓冲区
  98. // 清空颜色缓冲区
  99. gl.clear(gl.COLOR_BUFFER_BIT);
  100. // gl.drawArrays(mode, first, count);
  101. // mode 表示绘制的方式
  102. // first 从那个顶点开始绘制
  103. // count 绘制几个顶点
  104. // gl.drawArrays(gl.POINTS, 0, n);
  105. gl.drawArrays(gl.TRIANGLES, 0, n); // 可以画出彩色三角形
  106. }
  107. main()
  108. </script>
  109. </body>
  110. </html>

5.3 图形装配,光栅化

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Clear canvas</title>
  6. </head>
  7. <body>
  8. <canvas id="webgl" width="400" height="400">
  9. Please use the browser supporting "canvas"
  10. </canvas>
  11. <script src="../lib/webgl-utils.js"></script>
  12. <script src="../lib/webgl-debug.js"></script>
  13. <script src="../lib/cuon-utils.js"></script>
  14. <script>
  15. // HelloTriangle_FragCoord.js (c) 2012 matsuda
  16. // Vertex shader program
  17. var VSHADER_SOURCE =
  18. 'attribute vec4 a_Position;\n' +
  19. 'void main() {\n' +
  20. ' gl_Position = a_Position;\n' +
  21. '}\n';
  22. // Fragment shader program
  23. var FSHADER_SOURCE =
  24. 'precision mediump float;\n' +
  25. 'uniform float u_Width;\n' +
  26. 'uniform float u_Height;\n' +
  27. 'void main() {\n' +
  28. ' gl_FragColor = vec4(gl_FragCoord.x/u_Width, 0.0, gl_FragCoord.y/u_Height, 1.0);\n' +
  29. '}\n';
  30. function main() {
  31. // Retrieve <canvas> element
  32. var canvas = document.getElementById('webgl');
  33. // Get the rendering context for WebGL
  34. var gl = getWebGLContext(canvas);
  35. if (!gl) {
  36. console.log('Failed to get the rendering context for WebGL');
  37. return;
  38. }
  39. // Initialize shaders
  40. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  41. console.log('Failed to intialize shaders.');
  42. return;
  43. }
  44. // Write the positions of vertices to a vertex shader
  45. var n = initVertexBuffers(gl);
  46. if (n < 0) {
  47. console.log('Failed to set the positions of the vertices');
  48. return;
  49. }
  50. // Specify the color for clearing <canvas>
  51. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  52. // Clear <canvas>
  53. gl.clear(gl.COLOR_BUFFER_BIT);
  54. // Draw the rectangle
  55. gl.drawArrays(gl.TRIANGLES, 0, n);
  56. }
  57. function initVertexBuffers(gl) {
  58. var vertices = new Float32Array([
  59. 0, 0.5, -0.5, -0.5, 0.5, -0.5
  60. ]);
  61. var n = 3; // The number of vertices
  62. // Create a buffer object
  63. var vertexBuffer = gl.createBuffer();
  64. if (!vertexBuffer) {
  65. console.log('Failed to create the buffer object');
  66. return -1;
  67. }
  68. // Bind the buffer object to target
  69. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  70. // Write date into the buffer object
  71. gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  72. // Pass the position of a point to a_Position variable
  73. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  74. if (a_Position < 0) {
  75. console.log('Failed to get the storage location of a_Position');
  76. return -1;
  77. }
  78. gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  79. var u_Width = gl.getUniformLocation(gl.program, 'u_Width');
  80. if (!u_Width) {
  81. console.log('Failed to get the storage location of u_Width');
  82. return;
  83. }
  84. var u_Height = gl.getUniformLocation(gl.program, 'u_Height');
  85. if (!u_Height) {
  86. console.log('Failed to get the storage location of u_Height');
  87. return;
  88. }
  89. // Pass the width and hight of the <canvas>
  90. gl.uniform1f(u_Width, gl.drawingBufferWidth);
  91. gl.uniform1f(u_Height, gl.drawingBufferHeight);
  92. // Enable the generic vertex attribute array
  93. gl.enableVertexAttribArray(a_Position);
  94. // Unbind the buffer object
  95. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  96. return n;
  97. }
  98. main();
  99. </script>
  100. </body>
  101. </html>

5.3纹理

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Clear canvas</title>
  6. </head>
  7. <body>
  8. <canvas id="webgl" width="400" height="400">
  9. Please use the browser supporting "canvas"
  10. </canvas>
  11. <script src="../lib/webgl-utils.js"></script>
  12. <script src="../lib/webgl-debug.js"></script>
  13. <script src="../lib/cuon-utils.js"></script>
  14. <script>
  15. // TexturedQuad.js (c) 2012 matsuda and kanda
  16. // Vertex shader program
  17. var VSHADER_SOURCE =
  18. 'attribute vec4 a_Position;\n' +
  19. 'attribute vec2 a_TexCoord;\n' +
  20. 'varying vec2 v_TexCoord;\n' +
  21. 'void main() {\n' +
  22. ' gl_Position = a_Position;\n' +
  23. ' v_TexCoord = a_TexCoord;\n' +
  24. '}\n';
  25. // Fragment shader program
  26. var FSHADER_SOURCE =
  27. '#ifdef GL_ES\n' +
  28. 'precision mediump float;\n' +
  29. '#endif\n' +
  30. // sampler2D 绑定到gl.TEXTURE_2D上的纹理数据类型
  31. // samplerCube 绑定到gl.TEXTURE_CUBE_MAP上的纹理数据类型
  32. 'uniform sampler2D u_Sampler;\n' +
  33. 'varying vec2 v_TexCoord;\n' +
  34. 'void main() {\n' +
  35. // 纹理映射
  36. // 使用GLSL ES内置函数texture2D来抽取纹素颜色。该函数返回
  37. // gl.RGB | gl.RGBA | gl.ALPHA | gl.LUMINANCE | gl.LUMINANCE_ALPHA
  38. ' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
  39. '}\n';
  40. function main() {
  41. // Retrieve <canvas> element
  42. var canvas = document.getElementById('webgl');
  43. // Get the rendering context for WebGL
  44. var gl = getWebGLContext(canvas);
  45. if (!gl) {
  46. console.log('Failed to get the rendering context for WebGL');
  47. return;
  48. }
  49. // Initialize shaders
  50. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  51. console.log('Failed to intialize shaders.');
  52. return;
  53. }
  54. // Set the vertex information
  55. var n = initVertexBuffers(gl);
  56. if (n < 0) {
  57. console.log('Failed to set the vertex information');
  58. return;
  59. }
  60. // Specify the color for clearing <canvas>
  61. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  62. // Set texture
  63. if (!initTextures(gl, n)) {
  64. console.log('Failed to intialize the texture.');
  65. return;
  66. }
  67. }
  68. function initVertexBuffers(gl) {
  69. var verticesTexCoords = new Float32Array([
  70. // 顶点坐标,纹理坐标
  71. -0.5, 0.5, 0.0, 1.0,
  72. -0.5, -0.5, 0.0, 0.0,
  73. 0.5, 0.5, 1.0, 1.0,
  74. 0.5, -0.5, 1.0, 0.0,
  75. ]);
  76. var n = 4;
  77. // Create the buffer object
  78. var vertexTexCoordBuffer = gl.createBuffer();
  79. if (!vertexTexCoordBuffer) {
  80. throw new TypeError("创建gl.Buffer失败")
  81. }
  82. // Bind the buffer object to target
  83. gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
  84. gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
  85. var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
  86. //Get the storage location of a_Position, assign and enable buffer
  87. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  88. if (a_Position < 0) {
  89. console.log('Failed to get the storage location of a_Position');
  90. return -1;
  91. }
  92. gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
  93. gl.enableVertexAttribArray(a_Position); // Enable the assignment of the buffer object
  94. // Get the storage location of a_TexCoord
  95. var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
  96. if (a_TexCoord < 0) {
  97. console.log('Failed to get the storage location of a_TexCoord');
  98. return -1;
  99. }
  100. // Assign the buffer object to a_TexCoord variable
  101. gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
  102. gl.enableVertexAttribArray(a_TexCoord); // Enable the assignment of the buffer object
  103. return n;
  104. }
  105. function initTextures(gl, n) {
  106. // 创建纹理对象 gl.deleteTexture 删除纹理对象
  107. var texture = gl.createTexture();
  108. if (!texture) {
  109. throw new TypeError("创建纹理对象失败");
  110. }
  111. // Get the storage location of u_Sampler
  112. var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
  113. if (!u_Sampler) {
  114. throw new TypeError("获取uniform变量失败");
  115. }
  116. var image = new Image(); // Create the image object
  117. // 设置图片加载完成的事件
  118. image.onload = function () { loadTexture(gl, n, texture, u_Sampler, image); };
  119. // 加载图片
  120. image.src = '../resources/sky.jpg';
  121. return true;
  122. }
  123. function loadTexture(gl, n, texture, u_Sampler, image) {
  124. // 对纹理图像进行y轴反转,png,bmp,jpg等格式图片的坐标系统的Y轴方向是相反的,因此,
  125. // 需要对图像进行y轴反转,才能正确显示图片
  126. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
  127. // 开启0号纹理单元,激活纹理单元
  128. // gl.TEXTURE0 ~ gl.TEXTURE7 webgl至少支持8个纹理单元
  129. // 在使用纹理单元前,需要激活
  130. gl.activeTexture(gl.TEXTURE0);
  131. // 绑定纹理对象
  132. // gl.TEXTURE_2D 二维纹理
  133. // gl.TEXTURE_CUBE_MAP 立方体纹理
  134. gl.bindTexture(gl.TEXTURE_2D, texture);
  135. // 配置纹理参数 gl.texParameteri(var1, var2, var3)
  136. // var1 = gl.TEXTURE_2D 二维纹理 | gl.TEXTURE_CUBE_MAP 立方体纹理
  137. // var2 = 纹理参数,下列值
  138. // gl.TEXTURE_MAG_FILTER 纹理放大 默认值 gl.LINEAR
  139. // gl.TEXTURE_MIN_FILTER 纹理缩小 默认值 gl.NEAREST_MIPMAP_LINEAR
  140. // gl.TEXTURE_WRAP_S 纹理水平填充 默认值 gl.REPAET
  141. // gl.TEXTURE_WRAP_T 纹理垂直填充 默认值 gl.REPAET
  142. // var3 = 纹理参数的值
  143. // gl.TEXTURE_MAG_FILTER 和 gl.TEXTURE_MIN_FILTER 支持的常量
  144. // gl.LINEAR | gl.NEAREST
  145. // gl.LINEAR 比 gl.NEAREST质量更好,它使用距离新像素中心最近的四个像素的颜色值的加权平均,作为新像素的值
  146. // gl.TEXTURE_WRAP_S 和 gl.TEXTURE_WRAP_T 支持的常量
  147. // gl.REPEAT 平铺式的重复纹理
  148. // gl.MIRRORED_REPEAT 镜像对称式的重复纹理
  149. // gl.CLAMP_TO_EDGE 使用纹理的边缘值
  150. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  151. // 配置纹理图像
  152. // gl.texImage2D(var1, var2, var3, var4, var5, var6)
  153. // var1 = gl.TEXTURE_2D 二维纹理 | gl.TEXTURE_CUBE_MAP 立方体纹理
  154. // var2 = 传入0 ,实际上该参数是给金字塔纹理准备的,暂时不涉及
  155. // var3 = 图片的内部格式,gl.RGB | gl.RGBA | gl.ALPHA | gl.LUMINANCE | gl.LUMINANCE_ALPHA
  156. // var4 = 纹理数据的格式,必须与var3的值一致
  157. // var5 = 纹理的数据类型
  158. // gl.UNSIGNED_BYTE 无符号整型,每个符号占一个字节
  159. // gl.UNSIGNED_SHORT_5_6_5 RGB: 每个分量分别占5、6、5比特
  160. // gl.UNSIGNED_SHORT_4_4_4_4 RGBA: 每个分量分别占4、4、4、4比特
  161. // gl.UNSIGNED_SHORT_5_5_5_1 RGBA: RGB每个分量分别占5比特,A分量占1比特
  162. // var6 = image
  163. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
  164. // 将0号纹理传递给着色器中的取样器变量
  165. // 也就是这个gl.TEXTURE0的编号传给u_Sampler
  166. gl.uniform1i(u_Sampler, 0);
  167. gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas>
  168. gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // Draw the rectangle
  169. }
  170. main();
  171. </script>
  172. </body>
  173. </html>

5.3.1 纹理texParameteri的使用

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Clear canvas</title>
  6. </head>
  7. <body>
  8. <canvas id="webgl" width="400" height="400">
  9. Please use the browser supporting "canvas"
  10. </canvas>
  11. <script src="../lib/webgl-utils.js"></script>
  12. <script src="../lib/webgl-debug.js"></script>
  13. <script src="../lib/cuon-utils.js"></script>
  14. <script>
  15. // TexturedQuad.js (c) 2012 matsuda and kanda
  16. // Vertex shader program
  17. var VSHADER_SOURCE =
  18. 'attribute vec4 a_Position;\n' +
  19. 'attribute vec2 a_TexCoord;\n' +
  20. 'varying vec2 v_TexCoord;\n' +
  21. 'void main() {\n' +
  22. ' gl_Position = a_Position;\n' +
  23. ' v_TexCoord = a_TexCoord;\n' +
  24. '}\n';
  25. // Fragment shader program
  26. var FSHADER_SOURCE =
  27. '#ifdef GL_ES\n' +
  28. 'precision mediump float;\n' +
  29. '#endif\n' +
  30. // sampler2D 绑定到gl.TEXTURE_2D上的纹理数据类型
  31. // samplerCube 绑定到gl.TEXTURE_CUBE_MAP上的纹理数据类型
  32. 'uniform sampler2D u_Sampler;\n' +
  33. 'varying vec2 v_TexCoord;\n' +
  34. 'void main() {\n' +
  35. // 纹理映射
  36. // 使用GLSL ES内置函数texture2D来抽取纹素颜色。该函数返回
  37. // gl.RGB | gl.RGBA | gl.ALPHA | gl.LUMINANCE | gl.LUMINANCE_ALPHA
  38. ' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
  39. '}\n';
  40. function main() {
  41. // Retrieve <canvas> element
  42. var canvas = document.getElementById('webgl');
  43. // Get the rendering context for WebGL
  44. var gl = getWebGLContext(canvas);
  45. if (!gl) {
  46. console.log('Failed to get the rendering context for WebGL');
  47. return;
  48. }
  49. // Initialize shaders
  50. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  51. console.log('Failed to intialize shaders.');
  52. return;
  53. }
  54. // Set the vertex information
  55. var n = initVertexBuffers(gl);
  56. if (n < 0) {
  57. console.log('Failed to set the vertex information');
  58. return;
  59. }
  60. // Specify the color for clearing <canvas>
  61. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  62. // Set texture
  63. if (!initTextures(gl, n)) {
  64. console.log('Failed to intialize the texture.');
  65. return;
  66. }
  67. }
  68. function initVertexBuffers(gl) {
  69. var verticesTexCoords = new Float32Array([
  70. // 顶点坐标,纹理坐标
  71. -0.5, 0.5, -0.3, 1.7,
  72. -0.5, -0.5, -0.3, -0.2,
  73. 0.5, 0.5, 1.7, 1.7,
  74. 0.5, -0.5, 1.7, -0.2,
  75. ]);
  76. var n = 4;
  77. // Create the buffer object
  78. var vertexTexCoordBuffer = gl.createBuffer();
  79. if (!vertexTexCoordBuffer) {
  80. throw new TypeError("创建gl.Buffer失败")
  81. }
  82. // Bind the buffer object to target
  83. gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
  84. gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
  85. var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
  86. //Get the storage location of a_Position, assign and enable buffer
  87. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  88. if (a_Position < 0) {
  89. console.log('Failed to get the storage location of a_Position');
  90. return -1;
  91. }
  92. gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
  93. gl.enableVertexAttribArray(a_Position); // Enable the assignment of the buffer object
  94. // Get the storage location of a_TexCoord
  95. var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
  96. if (a_TexCoord < 0) {
  97. console.log('Failed to get the storage location of a_TexCoord');
  98. return -1;
  99. }
  100. // Assign the buffer object to a_TexCoord variable
  101. gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
  102. gl.enableVertexAttribArray(a_TexCoord); // Enable the assignment of the buffer object
  103. return n;
  104. }
  105. function initTextures(gl, n) {
  106. // 创建纹理对象 gl.deleteTexture 删除纹理对象
  107. var texture = gl.createTexture();
  108. if (!texture) {
  109. throw new TypeError("创建纹理对象失败");
  110. }
  111. // Get the storage location of u_Sampler
  112. var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
  113. if (!u_Sampler) {
  114. throw new TypeError("获取uniform变量失败");
  115. }
  116. var image = new Image(); // Create the image object
  117. // 设置图片加载完成的事件
  118. image.onload = function () { loadTexture(gl, n, texture, u_Sampler, image); };
  119. // 加载图片
  120. image.src = '../resources/sky.jpg';
  121. return true;
  122. }
  123. function loadTexture(gl, n, texture, u_Sampler, image) {
  124. // 对纹理图像进行y轴反转,png,bmp,jpg等格式图片的坐标系统的Y轴方向是相反的,因此,
  125. // 需要对图像进行y轴反转,才能正确显示图片
  126. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
  127. // 开启0号纹理单元,激活纹理单元
  128. // gl.TEXTURE0 ~ gl.TEXTURE7 webgl至少支持8个纹理单元
  129. // 在使用纹理单元前,需要激活
  130. gl.activeTexture(gl.TEXTURE0);
  131. // 绑定纹理对象
  132. // gl.TEXTURE_2D 二维纹理
  133. // gl.TEXTURE_CUBE_MAP 立方体纹理
  134. gl.bindTexture(gl.TEXTURE_2D, texture);
  135. // 配置纹理参数 gl.texParameteri(var1, var2, var3)
  136. // var1 = gl.TEXTURE_2D 二维纹理 | gl.TEXTURE_CUBE_MAP 立方体纹理
  137. // var2 = 纹理参数,下列值
  138. // gl.TEXTURE_MAG_FILTER 纹理放大 默认值 gl.LINEAR
  139. // gl.TEXTURE_MIN_FILTER 纹理缩小 默认值 gl.NEAREST_MIPMAP_LINEAR
  140. // gl.TEXTURE_WRAP_S 纹理水平填充 默认值 gl.REPAET
  141. // gl.TEXTURE_WRAP_T 纹理垂直填充 默认值 gl.REPAET
  142. // var3 = 纹理参数的值
  143. // gl.TEXTURE_MAG_FILTER 和 gl.TEXTURE_MIN_FILTER 支持的常量
  144. // gl.LINEAR | gl.NEAREST
  145. // gl.LINEAR 比 gl.NEAREST质量更好,它使用距离新像素中心最近的四个像素的颜色值的加权平均,作为新像素的值
  146. // gl.TEXTURE_WRAP_S 和 gl.TEXTURE_WRAP_T 支持的常量
  147. // gl.REPEAT 平铺式的重复纹理
  148. // gl.MIRRORED_REPEAT 镜像对称式的重复纹理
  149. // gl.CLAMP_TO_EDGE 使用纹理的边缘值
  150. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  151. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  152. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
  153. // 配置纹理图像
  154. // gl.texImage2D(var1, var2, var3, var4, var5, var6)
  155. // var1 = gl.TEXTURE_2D 二维纹理 | gl.TEXTURE_CUBE_MAP 立方体纹理
  156. // var2 = 传入0 ,实际上该参数是给金字塔纹理准备的,暂时不涉及
  157. // var3 = 图片的内部格式,gl.RGB | gl.RGBA | gl.ALPHA | gl.LUMINANCE | gl.LUMINANCE_ALPHA
  158. // var4 = 纹理数据的格式,必须与var3的值一致
  159. // var5 = 纹理的数据类型
  160. // gl.UNSIGNED_BYTE 无符号整型,每个符号占一个字节
  161. // gl.UNSIGNED_SHORT_5_6_5 RGB: 每个分量分别占5、6、5比特
  162. // gl.UNSIGNED_SHORT_4_4_4_4 RGBA: 每个分量分别占4、4、4、4比特
  163. // gl.UNSIGNED_SHORT_5_5_5_1 RGBA: RGB每个分量分别占5比特,A分量占1比特
  164. // var6 = image
  165. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
  166. // 将0号纹理传递给着色器中的取样器变量
  167. // 也就是这个gl.TEXTURE0的编号传给u_Sampler
  168. gl.uniform1i(u_Sampler, 0);
  169. gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas>
  170. gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // Draw the rectangle
  171. }
  172. main();
  173. </script>
  174. </body>
  175. </html>

5.3.2 使用多幅纹理

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Clear canvas</title>
  6. </head>
  7. <body>
  8. <canvas id="webgl" width="400" height="400">
  9. Please use the browser supporting "canvas"
  10. </canvas>
  11. <script src="../lib/webgl-utils.js"></script>
  12. <script src="../lib/webgl-debug.js"></script>
  13. <script src="../lib/cuon-utils.js"></script>
  14. <script>
  15. // TexturedQuad.js (c) 2012 matsuda and kanda
  16. // Vertex shader program
  17. var VSHADER_SOURCE =
  18. 'attribute vec4 a_Position;\n' +
  19. 'attribute vec2 a_TexCoord;\n' +
  20. 'varying vec2 v_TexCoord;\n' +
  21. 'void main() {\n' +
  22. ' gl_Position = a_Position;\n' +
  23. ' v_TexCoord = a_TexCoord;\n' +
  24. '}\n';
  25. // Fragment shader program
  26. var FSHADER_SOURCE =
  27. '#ifdef GL_ES\n' +
  28. 'precision mediump float;\n' +
  29. '#endif\n' +
  30. // sampler2D 绑定到gl.TEXTURE_2D上的纹理数据类型
  31. // samplerCube 绑定到gl.TEXTURE_CUBE_MAP上的纹理数据类型
  32. 'uniform sampler2D u_Sampler0;\n' +
  33. 'uniform sampler2D u_Sampler1;\n' +
  34. 'varying vec2 v_TexCoord;\n' +
  35. 'void main() {\n' +
  36. ' vec4 color1 = texture2D(u_Sampler0, v_TexCoord);\n' +
  37. ' vec4 color0 = texture2D(u_Sampler1, v_TexCoord);\n' +
  38. ' gl_FragColor = color0 * color1;\n' +
  39. '}\n';
  40. function main() {
  41. // Retrieve <canvas> element
  42. var canvas = document.getElementById('webgl');
  43. // Get the rendering context for WebGL
  44. var gl = getWebGLContext(canvas);
  45. if (!gl) {
  46. console.log('Failed to get the rendering context for WebGL');
  47. return;
  48. }
  49. // Initialize shaders
  50. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  51. console.log('Failed to intialize shaders.');
  52. return;
  53. }
  54. // Set the vertex information
  55. var n = initVertexBuffers(gl);
  56. if (n < 0) {
  57. console.log('Failed to set the vertex information');
  58. return;
  59. }
  60. // Specify the color for clearing <canvas>
  61. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  62. // Set texture
  63. if (!initTextures(gl, n)) {
  64. console.log('Failed to intialize the texture.');
  65. return;
  66. }
  67. }
  68. function initVertexBuffers(gl) {
  69. var verticesTexCoords = new Float32Array([
  70. // 顶点坐标,纹理坐标
  71. -0.5, 0.5, 0.0, 1.0,
  72. -0.5, -0.5, 0.0, 0.0,
  73. 0.5, 0.5, 1.0, 1.0,
  74. 0.5, -0.5, 1.0, 0.0,
  75. ]);
  76. var n = 4;
  77. // Create the buffer object
  78. var vertexTexCoordBuffer = gl.createBuffer();
  79. if (!vertexTexCoordBuffer) {
  80. throw new TypeError("创建gl.Buffer失败")
  81. }
  82. // Bind the buffer object to target
  83. gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
  84. gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
  85. var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
  86. //Get the storage location of a_Position, assign and enable buffer
  87. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  88. if (a_Position < 0) {
  89. console.log('Failed to get the storage location of a_Position');
  90. return -1;
  91. }
  92. gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
  93. gl.enableVertexAttribArray(a_Position); // Enable the assignment of the buffer object
  94. // Get the storage location of a_TexCoord
  95. var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
  96. if (a_TexCoord < 0) {
  97. console.log('Failed to get the storage location of a_TexCoord');
  98. return -1;
  99. }
  100. // Assign the buffer object to a_TexCoord variable
  101. gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
  102. gl.enableVertexAttribArray(a_TexCoord); // Enable the assignment of the buffer object
  103. return n;
  104. }
  105. function initTextures(gl, n) {
  106. // 创建纹理对象 gl.deleteTexture 删除纹理对象
  107. var texture0 = gl.createTexture();
  108. var texture1 = gl.createTexture();
  109. if (!texture0 || !texture1) {
  110. throw new TypeError("创建纹理对象失败");
  111. }
  112. // Get the storage location of u_Sampler
  113. var u_Sampler0 = gl.getUniformLocation(gl.program, 'u_Sampler0');
  114. var u_Sampler1 = gl.getUniformLocation(gl.program, 'u_Sampler1');
  115. if (!u_Sampler0 || !u_Sampler1) {
  116. throw new TypeError("获取uniform变量失败");
  117. }
  118. var image0 = new Image();
  119. var image1 = new Image();
  120. // 设置图片加载完成的事件
  121. image0.onload = function () { loadTexture(gl, n, texture0, u_Sampler0, image0, 0); };
  122. image1.onload = function () { loadTexture(gl, n, texture1, u_Sampler1, image1, 1); };
  123. // 加载图片
  124. image0.src = '../resources/sky.jpg';
  125. image1.src = '../resources/circle.gif';
  126. return true;
  127. }
  128. var g_texUnit0 = false, g_texUnit1 = false;
  129. function loadTexture(gl, n, texture, u_Sampler, image, texUnit) {
  130. // 对纹理图像进行y轴反转,png,bmp,jpg等格式图片的坐标系统的Y轴方向是相反的,因此,
  131. // 需要对图像进行y轴反转,才能正确显示图片
  132. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
  133. // 开启0号纹理单元,激活纹理单元
  134. // gl.TEXTURE0 ~ gl.TEXTURE7 webgl至少支持8个纹理单元
  135. // 在使用纹理单元前,需要激活
  136. if (texUnit === 0) {
  137. gl.activeTexture(gl.TEXTURE0);
  138. g_texUnit0 = true;
  139. } else {
  140. gl.activeTexture(gl.TEXTURE1);
  141. g_texUnit1 = true;
  142. }
  143. // 绑定纹理对象
  144. // gl.TEXTURE_2D 二维纹理
  145. // gl.TEXTURE_CUBE_MAP 立方体纹理
  146. gl.bindTexture(gl.TEXTURE_2D, texture);
  147. // 配置纹理参数 gl.texParameteri(var1, var2, var3)
  148. // var1 = gl.TEXTURE_2D 二维纹理 | gl.TEXTURE_CUBE_MAP 立方体纹理
  149. // var2 = 纹理参数,下列值
  150. // gl.TEXTURE_MAG_FILTER 纹理放大 默认值 gl.LINEAR
  151. // gl.TEXTURE_MIN_FILTER 纹理缩小 默认值 gl.NEAREST_MIPMAP_LINEAR
  152. // gl.TEXTURE_WRAP_S 纹理水平填充 默认值 gl.REPAET
  153. // gl.TEXTURE_WRAP_T 纹理垂直填充 默认值 gl.REPAET
  154. // var3 = 纹理参数的值
  155. // gl.TEXTURE_MAG_FILTER 和 gl.TEXTURE_MIN_FILTER 支持的常量
  156. // gl.LINEAR | gl.NEAREST
  157. // gl.LINEAR 比 gl.NEAREST质量更好,它使用距离新像素中心最近的四个像素的颜色值的加权平均,作为新像素的值
  158. // gl.TEXTURE_WRAP_S 和 gl.TEXTURE_WRAP_T 支持的常量
  159. // gl.REPEAT 平铺式的重复纹理
  160. // gl.MIRRORED_REPEAT 镜像对称式的重复纹理
  161. // gl.CLAMP_TO_EDGE 使用纹理的边缘值
  162. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  163. // 配置纹理图像
  164. // gl.texImage2D(var1, var2, var3, var4, var5, var6)
  165. // var1 = gl.TEXTURE_2D 二维纹理 | gl.TEXTURE_CUBE_MAP 立方体纹理
  166. // var2 = 传入0 ,实际上该参数是给金字塔纹理准备的,暂时不涉及
  167. // var3 = 图片的内部格式,gl.RGB | gl.RGBA | gl.ALPHA | gl.LUMINANCE | gl.LUMINANCE_ALPHA
  168. // var4 = 纹理数据的格式,必须与var3的值一致
  169. // var5 = 纹理的数据类型
  170. // gl.UNSIGNED_BYTE 无符号整型,每个符号占一个字节
  171. // gl.UNSIGNED_SHORT_5_6_5 RGB: 每个分量分别占5、6、5比特
  172. // gl.UNSIGNED_SHORT_4_4_4_4 RGBA: 每个分量分别占4、4、4、4比特
  173. // gl.UNSIGNED_SHORT_5_5_5_1 RGBA: RGB每个分量分别占5比特,A分量占1比特
  174. // var6 = image
  175. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  176. // 将0号纹理传递给着色器中的取样器变量
  177. // 也就是这个gl.TEXTURE0的编号传给u_Sampler
  178. gl.uniform1i(u_Sampler, texUnit);
  179. gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas>
  180. if (g_texUnit0 && g_texUnit1) {
  181. gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // Draw the rectangle
  182. }
  183. }
  184. main();
  185. </script>
  186. </body>
  187. </html>