一. 逻辑部分

缩放和平移一样简单。
让我们将位置乘以期望的缩放值,这是前例中的变化部分。

  1. // 这是一段关于缩放区域的一段的代码;
  2. <script id="vertex-shader-2d" type="x-shader/x-vertex">
  3. attribute vec2 a_position;
  4. uniform vec2 u_resolution;
  5. uniform vec2 u_translation;
  6. uniform vec2 u_rotation;
  7. uniform vec2 u_scale;
  8. void main() {
  9. // 缩放
  10. vec2 scaledPosition = a_position * u_scale;
  11. // 旋转
  12. vec2 rotatedPosition = vec2(
  13. scaledPosition.x * u_rotation.y + scaledPosition.y * u_rotation.x,
  14. scaledPosition.y * u_rotation.y - scaledPosition.x * u_rotation.x);
  15. // 平移
  16. vec2 position = rotatedPosition + u_translation;
  17. // 然后需要在JavaScript中绘制的地方设置缩放量。
  18. ...
  19. var scaleLocation = gl.getUniformLocation(program, "u_scale");
  20. ...
  21. var scale = [1, 1];
  22. ...
  23. // 绘制场景
  24. function drawScene() {
  25. ...
  26. // 设置平移
  27. gl.uniform2fv(translationLocation, translation);
  28. // 设置旋转
  29. gl.uniform2fv(rotationLocation, rotation);
  30. // 设置缩放
  31. gl.uniform2fv(scaleLocation, scale);
  32. // 绘制几何体
  33. var primitiveType = gl.TRIANGLES;
  34. var offset = 0;
  35. var count = 18; // 6 个三角形组成 'F', 每个三角形 3 个点
  36. gl.drawArrays(primitiveType, offset, count);
  37. }

二. 全部代码

  1. "use strict";
  2. function main() {
  3. // Get A WebGL context
  4. /** @type {HTMLCanvasElement} */
  5. var canvas = document.querySelector("#canvas");
  6. var gl = canvas.getContext("webgl");
  7. if (!gl) {
  8. return;
  9. }
  10. // setup GLSL program
  11. var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-2d", "fragment-shader-2d"]);
  12. // look up where the vertex data needs to go.
  13. var positionLocation = gl.getAttribLocation(program, "a_position");
  14. // lookup uniforms
  15. var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
  16. var colorLocation = gl.getUniformLocation(program, "u_color");
  17. var translationLocation = gl.getUniformLocation(program, "u_translation");
  18. var rotationLocation = gl.getUniformLocation(program, "u_rotation");
  19. var scaleLocation = gl.getUniformLocation(program, "u_scale");
  20. // Create a buffer to put positions in
  21. var positionBuffer = gl.createBuffer();
  22. // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
  23. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  24. // Put geometry data into buffer
  25. setGeometry(gl);
  26. var translation = [100, 150];
  27. var rotation = [0, 1];
  28. var scale = [1, 1];
  29. var color = [Math.random(), Math.random(), Math.random(), 1];
  30. drawScene();
  31. // Setup a ui.
  32. webglLessonsUI.setupSlider("#x", {value: translation[0], slide: updatePosition(0), max: gl.canvas.width });
  33. webglLessonsUI.setupSlider("#y", {value: translation[1], slide: updatePosition(1), max: gl.canvas.height});
  34. webglLessonsUI.setupSlider("#angle", {slide: updateAngle, max: 360});
  35. webglLessonsUI.setupSlider("#scaleX", {value: scale[0], slide: updateScale(0), min: -5, max: 5, step: 0.01, precision: 2});
  36. webglLessonsUI.setupSlider("#scaleY", {value: scale[1], slide: updateScale(1), min: -5, max: 5, step: 0.01, precision: 2});
  37. function updatePosition(index) {
  38. return function(event, ui) {
  39. translation[index] = ui.value;
  40. drawScene();
  41. };
  42. }
  43. function updateAngle(event, ui) {
  44. var angleInDegrees = 360 - ui.value;
  45. var angleInRadians = angleInDegrees * Math.PI / 180;
  46. rotation[0] = Math.sin(angleInRadians);
  47. rotation[1] = Math.cos(angleInRadians);
  48. drawScene();
  49. }
  50. function updateScale(index) {
  51. return function(event, ui) {
  52. scale[index] = ui.value;
  53. drawScene();
  54. };
  55. }
  56. // Draw the scene.
  57. function drawScene() {
  58. webglUtils.resizeCanvasToDisplaySize(gl.canvas);
  59. // Tell WebGL how to convert from clip space to pixels
  60. gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  61. // Clear the canvas.
  62. gl.clear(gl.COLOR_BUFFER_BIT);
  63. // Tell it to use our program (pair of shaders)
  64. gl.useProgram(program);
  65. // Turn on the attribute
  66. gl.enableVertexAttribArray(positionLocation);
  67. // Bind the position buffer.
  68. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  69. // Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
  70. var size = 2; // 2 components per iteration
  71. var type = gl.FLOAT; // the data is 32bit floats
  72. var normalize = false; // don't normalize the data
  73. var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
  74. var offset = 0; // start at the beginning of the buffer
  75. gl.vertexAttribPointer(
  76. positionLocation, size, type, normalize, stride, offset);
  77. // set the resolution
  78. gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height);
  79. // set the color
  80. gl.uniform4fv(colorLocation, color);
  81. // Set the translation.
  82. gl.uniform2fv(translationLocation, translation);
  83. // Set the rotation.
  84. gl.uniform2fv(rotationLocation, rotation);
  85. // Set the scale.
  86. gl.uniform2fv(scaleLocation, scale);
  87. // Draw the geometry.
  88. var primitiveType = gl.TRIANGLES;
  89. var offset = 0;
  90. var count = 18; // 6 triangles in the 'F', 3 points per triangle
  91. gl.drawArrays(primitiveType, offset, count);
  92. }
  93. }
  94. // Fill the buffer with the values that define a letter 'F'.
  95. function setGeometry(gl) {
  96. gl.bufferData(
  97. gl.ARRAY_BUFFER,
  98. new Float32Array([
  99. // left column
  100. 0, 0,
  101. 30, 0,
  102. 0, 150,
  103. 0, 150,
  104. 30, 0,
  105. 30, 150,
  106. // top rung
  107. 30, 0,
  108. 100, 0,
  109. 30, 30,
  110. 30, 30,
  111. 100, 0,
  112. 100, 30,
  113. // middle rung
  114. 30, 60,
  115. 67, 60,
  116. 30, 90,
  117. 30, 90,
  118. 67, 60,
  119. 67, 90,
  120. ]),
  121. gl.STATIC_DRAW);
  122. }
  123. main();
  124. // html
  125. <canvas id="canvas"></canvas>
  126. <div id="uiContainer">
  127. <div id="ui">
  128. <div id="x"></div>
  129. <div id="y"></div>
  130. <div id="angle"></div>
  131. <div id="scaleX"></div>
  132. <div id="scaleY"></div>
  133. </div>
  134. </div>
  135. <!-- vertex shader -->
  136. <script id="vertex-shader-2d" type="x-shader/x-vertex">
  137. attribute vec2 a_position;
  138. uniform vec2 u_resolution;
  139. uniform vec2 u_translation;
  140. uniform vec2 u_rotation;
  141. uniform vec2 u_scale;
  142. void main() {
  143. // Scale the position
  144. vec2 scaledPosition = a_position * u_scale;
  145. // Rotate the position
  146. vec2 rotatedPosition = vec2(
  147. scaledPosition.x * u_rotation.y + scaledPosition.y * u_rotation.x,
  148. scaledPosition.y * u_rotation.y - scaledPosition.x * u_rotation.x);
  149. // Add in the translation.
  150. vec2 position = rotatedPosition + u_translation;
  151. // convert the position from pixels to 0.0 to 1.0
  152. vec2 zeroToOne = position / u_resolution;
  153. // convert from 0->1 to 0->2
  154. vec2 zeroToTwo = zeroToOne * 2.0;
  155. // convert from 0->2 to -1->+1 (clipspace)
  156. vec2 clipSpace = zeroToTwo - 1.0;
  157. gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
  158. }
  159. </script>
  160. <!-- fragment shader -->
  161. <script id="fragment-shader-2d" type="x-shader/x-fragment">
  162. precision mediump float;
  163. uniform vec4 u_color;
  164. void main() {
  165. gl_FragColor = u_color;
  166. }
  167. </script>https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
  168. <script src="https://webglfundamentals.org/webgl/resources/webgl-lessons-ui.js"></script>