当前位置:   article > 正文

使用 WebGL 创建 3D 对象_webgl 3d创建

webgl 3d创建

使用 WebGL 创建 3D 对象 - Web API 接口参考 | MDN (mozilla.org)icon-default.png?t=N7T8https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL

现在让我们给之前的正方形添加五个面从而可以创建一个三维的立方体。最简单的方式就是通过调用方法 gl.drawElements() 使用顶点数组列表来替换之前的通过方法gl.drawArrays() 直接使用顶点数组。而顶点数组列表里保存着将会被引用到一个个独立的顶点。

其实现在会存在这样一个问题:每个面需要 4 个顶点,而每个顶点会被 3 个面共享。我们会创建一个包含 24 个顶点的数组列表,通过使用数组下标来索引顶点,然后把这些用于索引的下标传递给渲染程序而不是直接把整个顶点数据传递过去,这样来减少数据传递。那么也许你就会问:那么使用 8 个顶点就好了,为什么要使用 24 个顶点呢?这是因为每个顶点虽然被 3 个面共享但是它在每个面上需要使用不同的颜色信息。24 个顶点中的每一个都会有独立的颜色信息,这就会造成每个顶点位置都会有 3 份副本。

定义立方体顶点位置

首先,更新 initBuffers() 函数中代码来创建立方体的顶点位置缓存区。现在的代码看起来和渲染正方形时的代码很相似,只是比之前的代码更长因为现在有了 24 个顶点(每个面使用 4 个顶点):

备注: 在“init-buffers.js”文件 initPositionBuffer() 函数中,用下面代码替换 positions

  1. const positions = [
  2. // Front face
  3. -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,
  4. // Back face
  5. -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
  6. // Top face
  7. -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
  8. // Bottom face
  9. -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
  10. // Right face
  11. 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0,
  12. // Left face
  13. -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
  14. ];

由于我们给顶点添加了 Z 分量,因此我们需要将 vertexPosition 属性的 numComponents 更新为 3。

备注: 在“draw-scene.js”文件 setPositionAttribute() 函数中,将 numComponents 从 2 改为 3:

const numComponents = 3;

定义顶点颜色

然后我们还要为每个顶点定义颜色。下面的代码首先为每个面定义颜色,然后用一个循环语句为每个顶点定义颜色信息。

备注: 在“init-buffers.js”文件 initColorBuffer() 函数中,用下面代码替换 colors 定义:

  1. const faceColors = [
  2. [1.0, 1.0, 1.0, 1.0], // Front face: white
  3. [1.0, 0.0, 0.0, 1.0], // Back face: red
  4. [0.0, 1.0, 0.0, 1.0], // Top face: green
  5. [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
  6. [1.0, 1.0, 0.0, 1.0], // Right face: yellow
  7. [1.0, 0.0, 1.0, 1.0], // Left face: purple
  8. ];
  9. // Convert the array of colors into a table for all the vertices.
  10. var colors = [];
  11. for (var j = 0; j < faceColors.length; ++j) {
  12. const c = faceColors[j];
  13. // Repeat each color four times for the four vertices of the face
  14. colors = colors.concat(c, c, c, c);
  15. }

定义元素(三角形)数组

既然已经创建好了顶点数组,接下来就要创建元素(三角形)数组了。

备注: 在“init-buffer.js”文件中添加下面的函数:

  1. function initIndexBuffer(gl) {
  2. const indexBuffer = gl.createBuffer();
  3. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  4. // This array defines each face as two triangles, using the
  5. // indices into the vertex array to specify each triangle's
  6. // position.
  7. const indices = [
  8. 0,
  9. 1,
  10. 2,
  11. 0,
  12. 2,
  13. 3, // front
  14. 4,
  15. 5,
  16. 6,
  17. 4,
  18. 6,
  19. 7, // back
  20. 8,
  21. 9,
  22. 10,
  23. 8,
  24. 10,
  25. 11, // top
  26. 12,
  27. 13,
  28. 14,
  29. 12,
  30. 14,
  31. 15, // bottom
  32. 16,
  33. 17,
  34. 18,
  35. 16,
  36. 18,
  37. 19, // right
  38. 20,
  39. 21,
  40. 22,
  41. 20,
  42. 22,
  43. 23, // left
  44. ];
  45. // Now send the element array to GL
  46. gl.bufferData(
  47. gl.ELEMENT_ARRAY_BUFFER,
  48. new Uint16Array(indices),
  49. gl.STATIC_DRAW,
  50. );
  51. return indexBuffer;
  52. }

indices 数组声明每一个面都使用两个三角形来渲染。通过立方体顶点数组的索引指定每个三角形的顶点。那么这个立方体就是由 12 个三角形组成的了。

备注: 在“init-buffers.js”文件 initBuffers()函数中,添加下面的代码替换之前的 return 代码片段:

  1. const indexBuffer = initIndexBuffer(gl);
  2. return {
  3. position: positionBuffer,
  4. color: colorBuffer,
  5. indices: indexBuffer,
  6. };

渲染立方体

接下来就需要在 drawScene() 函数里添加代码使用立方体顶点索引数据来渲染这个立方体了。代码里添加了对 gl.bindBuffer() 和 gl.drawElements()的调用:

备注: 在 drawScene() 函数中,gl.useProgram 代码前添加如下代码:

JSCopy to Clipboard

  1. // Tell WebGL which indices to use to index the vertices
  2. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);

备注: 在“draw-scene.js”文件 drawScene() 函数中,用下面这段代码替换之前 gl.drawArrays()

  1. {
  2. const vertexCount = 36;
  3. const type = gl.UNSIGNED_SHORT;
  4. const offset = 0;
  5. gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
  6. }

立方体的每个面都由 2 个三角形组成,那就是每个面需要 6 个顶点,或者说总共 36 个顶点,尽管有许多重复的。然而,因为索引数组的每个元素都是简单的整数类型,所以每一帧动画需要传递给渲染程序的数据也不是很多。

最后,让我们把变量 squareRotation 替换成 cubeRotation 并添加 X 轴的第二个旋转。

备注: 在“webgl-demo.js”文件的头部,把变量 squareRotation 替换成 cubeRotation

JSCopy to Clipboard

let cubeRotation = 0.0;

备注: 在 drawScene() 函数声明中,将变量 squareRotation 替换成 cubeRotation

JSCopy to Clipboard

function drawScene(gl, programInfo, buffers, cubeRotation) {

备注: 在 drawScene() 函数中,用下面代码替换之前的 mat4.rotate 函数:

  1. mat4.rotate(
  2. modelViewMatrix, // destination matrix
  3. modelViewMatrix, // matrix to rotate
  4. cubeRotation, // amount to rotate in radians
  5. [0, 0, 1],
  6. ); // axis to rotate around (Z)
  7. mat4.rotate(
  8. modelViewMatrix, // destination matrix
  9. modelViewMatrix, // matrix to rotate
  10. cubeRotation * 0.7, // amount to rotate in radians
  11. [0, 1, 0],
  12. ); // axis to rotate around (Y)
  13. mat4.rotate(
  14. modelViewMatrix, // destination matrix
  15. modelViewMatrix, // matrix to rotate
  16. cubeRotation * 0.3, // amount to rotate in radians
  17. [1, 0, 0],
  18. ); // axis to rotate around (X)

备注: 在 main() 函数中,替换 drawScene() 函数调用参数中的 squareRotation 为 cubeRotation

  1. drawScene(gl, programInfo, buffers, cubeRotation);
  2. cubeRotation += deltaTime;

到现在为止,我们已经创建了一个颜色生动的并且会在场景中移动和旋转的立方体,这一定很酷吧。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/716641
推荐阅读
相关标签
  

闽ICP备14008679号