ShadowMesh.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import {
  2. Matrix4,
  3. Mesh,
  4. MeshBasicMaterial,
  5. EqualStencilFunc,
  6. IncrementStencilOp
  7. } from 'three';
  8. const _shadowMatrix = new Matrix4();
  9. /**
  10. * A Shadow Mesh that follows a shadow-casting mesh in the scene,
  11. * but is confined to a single plane. This technique can be used as
  12. * a very performant alternative to classic shadow mapping. However,
  13. * it has serious limitations like:
  14. *
  15. * - Shadows can only be casted on flat planes.
  16. * - No soft shadows support.
  17. *
  18. * ```js
  19. * const cubeShadow = new ShadowMesh( cube );
  20. * scene.add( cubeShadow );
  21. * ```
  22. *
  23. * @augments Mesh
  24. */
  25. class ShadowMesh extends Mesh {
  26. /**
  27. * Constructs a new shadow mesh.
  28. *
  29. * @param {Mesh} mesh - The shadow-casting reference mesh.
  30. */
  31. constructor( mesh ) {
  32. const shadowMaterial = new MeshBasicMaterial( {
  33. color: 0x000000,
  34. transparent: true,
  35. opacity: 0.6,
  36. depthWrite: false,
  37. stencilWrite: true,
  38. stencilFunc: EqualStencilFunc,
  39. stencilRef: 0,
  40. stencilZPass: IncrementStencilOp
  41. } );
  42. super( mesh.geometry, shadowMaterial );
  43. /**
  44. * This flag can be used for type testing.
  45. *
  46. * @type {boolean}
  47. * @readonly
  48. * @default true
  49. */
  50. this.isShadowMesh = true;
  51. /**
  52. * Represent the world matrix of the reference mesh.
  53. *
  54. * @type {Matrix4}
  55. */
  56. this.meshMatrix = mesh.matrixWorld;
  57. /**
  58. * Overwritten to disable view-frustum culling by default.
  59. *
  60. * @type {boolean}
  61. * @default false
  62. */
  63. this.frustumCulled = false;
  64. /**
  65. * Overwritten to disable automatic matrix update. The local
  66. * matrix is computed manually in {@link ShadowMesh#update}.
  67. *
  68. * @type {boolean}
  69. * @default false
  70. */
  71. this.matrixAutoUpdate = false;
  72. }
  73. /**
  74. * Updates the shadow mesh so it follows its shadow-casting reference mesh.
  75. *
  76. * @param {Plane} plane - The plane onto the shadow mesh is projected.
  77. * @param {Vector4} lightPosition4D - The light position.
  78. */
  79. update( plane, lightPosition4D ) {
  80. // based on https://www.opengl.org/archives/resources/features/StencilTalk/tsld021.htm
  81. const dot = plane.normal.x * lightPosition4D.x +
  82. plane.normal.y * lightPosition4D.y +
  83. plane.normal.z * lightPosition4D.z +
  84. - plane.constant * lightPosition4D.w;
  85. const sme = _shadowMatrix.elements;
  86. sme[ 0 ] = dot - lightPosition4D.x * plane.normal.x;
  87. sme[ 4 ] = - lightPosition4D.x * plane.normal.y;
  88. sme[ 8 ] = - lightPosition4D.x * plane.normal.z;
  89. sme[ 12 ] = - lightPosition4D.x * - plane.constant;
  90. sme[ 1 ] = - lightPosition4D.y * plane.normal.x;
  91. sme[ 5 ] = dot - lightPosition4D.y * plane.normal.y;
  92. sme[ 9 ] = - lightPosition4D.y * plane.normal.z;
  93. sme[ 13 ] = - lightPosition4D.y * - plane.constant;
  94. sme[ 2 ] = - lightPosition4D.z * plane.normal.x;
  95. sme[ 6 ] = - lightPosition4D.z * plane.normal.y;
  96. sme[ 10 ] = dot - lightPosition4D.z * plane.normal.z;
  97. sme[ 14 ] = - lightPosition4D.z * - plane.constant;
  98. sme[ 3 ] = - lightPosition4D.w * plane.normal.x;
  99. sme[ 7 ] = - lightPosition4D.w * plane.normal.y;
  100. sme[ 11 ] = - lightPosition4D.w * plane.normal.z;
  101. sme[ 15 ] = dot - lightPosition4D.w * - plane.constant;
  102. this.matrix.multiplyMatrices( _shadowMatrix, this.meshMatrix );
  103. }
  104. }
  105. export { ShadowMesh };
粤ICP备19079148号