分组

与2D一样,3D扩展支持分组,我们可以创建Group3d元素。

  1. const {Scene} = spritejs;
  2. const {Cube, Sphere, Group3d, shaders} = spritejs.ext3d;
  3. const container = document.getElementById('container');
  4. const scene = new Scene({
  5. container,
  6. displayRatio: 2,
  7. });
  8. const layer = scene.layer3d('fglayer', {
  9. camera: {
  10. fov: 35,
  11. pos: [5, 3, 6],
  12. },
  13. });
  14. layer.camera.lookAt([0, -0.5, 0]);
  15. const program = layer.createProgram({
  16. ...shaders.NORMAL,
  17. cullFace: null,
  18. });
  19. const s1 = new Sphere(program, {
  20. phiLength: Math.PI, // 半球
  21. x: -1,
  22. rotateY: -90,
  23. });
  24. const s2 = s1.cloneNode();
  25. s2.attr({
  26. x: 1,
  27. rotateY: 90,
  28. });
  29. const c = new Cube(program, {
  30. rotateY: 45,
  31. scale: 0.5,
  32. });
  33. const group = new Group3d();
  34. group.append(s1, s2, c);
  35. layer.append(group);
  36. group.animate([
  37. {rotateY: 0},
  38. {rotateY: 360},
  39. ], {
  40. duration: 19000,
  41. iterations: Infinity,
  42. });
  43. c.animate([
  44. {rotateY: 0},
  45. {rotateY: 360},
  46. ], {
  47. duration: 11000,
  48. iterations: Infinity,
  49. });

在3D扩展中,layer上有一个默认的分组root,它是所有子元素共同的group,所以,上面的代码可以简化为:

  1. const {Scene} = spritejs;
  2. const {Cube, Sphere, shaders} = spritejs.ext3d;
  3. const container = document.getElementById('container');
  4. const scene = new Scene({
  5. container,
  6. displayRatio: 2,
  7. });
  8. const layer = scene.layer3d('fglayer', {
  9. camera: {
  10. fov: 35,
  11. pos: [5, 3, 6],
  12. },
  13. });
  14. layer.camera.lookAt([0, -0.5, 0]);
  15. const program = layer.createProgram({
  16. ...shaders.NORMAL,
  17. cullFace: null,
  18. });
  19. const s1 = new Sphere(program, {
  20. phiLength: Math.PI, // 半球
  21. x: -1,
  22. rotateY: -90,
  23. });
  24. const s2 = s1.cloneNode();
  25. s2.attr({
  26. x: 1,
  27. rotateY: 90,
  28. });
  29. const c = new Cube(program, {
  30. rotateY: 45,
  31. scale: 0.5,
  32. });
  33. layer.append(s1, s2, c);
  34. layer.root.animate([
  35. {rotateY: 0},
  36. {rotateY: 360},
  37. ], {
  38. duration: 19000,
  39. iterations: Infinity,
  40. });
  41. c.animate([
  42. {rotateY: 0},
  43. {rotateY: 360},
  44. ], {
  45. duration: 11000,
  46. iterations: Infinity,
  47. });

与2D不同的是,3D中的一切元素都是Group3d的派生类,因此我们也可以将元素直接append到任意一个3D元素上。

  1. const {Scene} = spritejs;
  2. const {Sphere, Cube} = spritejs.ext3d;
  3. const container = document.getElementById('container');
  4. const scene = new Scene({
  5. container,
  6. displayRatio: 2,
  7. });
  8. const layer = scene.layer3d('fglayer', {
  9. camera: {
  10. fov: 35,
  11. },
  12. ambientColor: 'white',
  13. });
  14. layer.camera.attributes.pos = [1, 7, 0];
  15. layer.camera.lookAt([0, 0, 0]);
  16. const vertex = /* glsl */ `
  17. precision highp float;
  18. precision highp int;
  19. attribute vec3 position;
  20. attribute vec3 normal;
  21. uniform mat4 modelViewMatrix;
  22. uniform mat4 projectionMatrix;
  23. uniform mat3 normalMatrix;
  24. varying vec3 vNormal;
  25. varying vec4 vMVPos;
  26. void main() {
  27. vNormal = normalize(normalMatrix * normal);
  28. vMVPos = modelViewMatrix * vec4(position, 1.0);
  29. gl_Position = projectionMatrix * vMVPos;
  30. }
  31. `;
  32. const fragment = /* glsl */ `
  33. precision highp float;
  34. precision highp int;
  35. varying vec3 vNormal;
  36. varying vec4 vMVPos;
  37. void main() {
  38. vec3 normal = normalize(vNormal);
  39. float lighting = dot(normal, normalize(vec3(-0.3, 0.8, 0.6)));
  40. vec3 color = vec3(1.0, 0.5, 0.2) * (1.0 - 0.5 * lighting) + vMVPos.xzy * 0.1;
  41. float dist = length(vMVPos);
  42. float fog = smoothstep(4.0, 10.0, dist);
  43. color = mix(color, vec3(1.0), fog);
  44. gl_FragColor.rgb = color;
  45. gl_FragColor.a = 1.0;
  46. }
  47. `;
  48. const program = layer.createProgram({
  49. vertex,
  50. fragment,
  51. });
  52. const sphere = new Sphere(program, {
  53. radius: 0.15,
  54. });
  55. const cube = new Cube(program, {
  56. width: 0.3,
  57. height: 0.3,
  58. depth: 0.3});
  59. const shapes = [cube];
  60. cube.speed = -0.5;
  61. layer.append(cube);
  62. // Create random array of shapes
  63. for(let i = 0; i < 50; i++) {
  64. const mesh = Math.random() > 0.5 ? cube : sphere;
  65. const shape = mesh.cloneNode();
  66. shape.attr({
  67. scale: Math.random() * 0.3 + 0.7,
  68. x: (Math.random() - 0.5) * 3,
  69. y: (Math.random() - 0.5) * 3,
  70. z: (Math.random() - 0.5) * 3,
  71. });
  72. shape.speed = (Math.random() - 0.5) * 0.7;
  73. // Attach them to a random, previously created shape
  74. const parent = shapes[Math.floor(Math.random() * shapes.length)];
  75. parent.append(shape);
  76. shapes.push(shape);
  77. }
  78. layer.tick((t) => {
  79. shapes.forEach((shape) => {
  80. shape.attributes.rotateY += 2 * shape.speed;
  81. shape.attributes.rotateX += 1.5 * shape.speed;
  82. shape.attributes.rotateZ += shape.speed;
  83. });
  84. });