LightShadow.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import { Matrix4 } from '../math/Matrix4.js';
  2. import { Vector2 } from '../math/Vector2.js';
  3. import { Vector3 } from '../math/Vector3.js';
  4. import { Vector4 } from '../math/Vector4.js';
  5. import { Frustum } from '../math/Frustum.js';
  6. const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
  7. const _lightPositionWorld = /*@__PURE__*/ new Vector3();
  8. const _lookTarget = /*@__PURE__*/ new Vector3();
  9. /**
  10. * Abstract base class for light shadow classes. These classes
  11. * represent the shadow configuration for different light types.
  12. *
  13. * @abstract
  14. */
  15. class LightShadow {
  16. /**
  17. * Constructs a new light shadow.
  18. *
  19. * @param {Camera} camera - The light's view of the world.
  20. */
  21. constructor( camera ) {
  22. /**
  23. * The light's view of the world.
  24. *
  25. * @type {Camera}
  26. */
  27. this.camera = camera;
  28. /**
  29. * The intensity of the shadow. The default is `1`.
  30. * Valid values are in the range `[0, 1]`.
  31. *
  32. * @type {number}
  33. * @default 1
  34. */
  35. this.intensity = 1;
  36. /**
  37. * Shadow map bias, how much to add or subtract from the normalized depth
  38. * when deciding whether a surface is in shadow.
  39. *
  40. * The default is `0`. Very tiny adjustments here (in the order of `0.0001`)
  41. * may help reduce artifacts in shadows.
  42. *
  43. * @type {number}
  44. * @default 0
  45. */
  46. this.bias = 0;
  47. /**
  48. * Defines how much the position used to query the shadow map is offset along
  49. * the object normal. The default is `0`. Increasing this value can be used to
  50. * reduce shadow acne especially in large scenes where light shines onto
  51. * geometry at a shallow angle. The cost is that shadows may appear distorted.
  52. *
  53. * @type {number}
  54. * @default 0
  55. */
  56. this.normalBias = 0;
  57. /**
  58. * Setting this to values greater than 1 will blur the edges of the shadow.
  59. * High values will cause unwanted banding effects in the shadows - a greater
  60. * map size will allow for a higher value to be used here before these effects
  61. * become visible.
  62. *
  63. * The property has no effect when the shadow map type is `PCFSoftShadowMap` and
  64. * and it is recommended to increase softness by decreasing the shadow map size instead.
  65. *
  66. * The property has no effect when the shadow map type is `BasicShadowMap`.
  67. *
  68. * @type {number}
  69. * @default 1
  70. */
  71. this.radius = 1;
  72. /**
  73. * The amount of samples to use when blurring a VSM shadow map.
  74. *
  75. * @type {number}
  76. * @default 8
  77. */
  78. this.blurSamples = 8;
  79. /**
  80. * Defines the width and height of the shadow map. Higher values give better quality
  81. * shadows at the cost of computation time. Values must be powers of two.
  82. *
  83. * @type {Vector2}
  84. * @default (512,512)
  85. */
  86. this.mapSize = new Vector2( 512, 512 );
  87. /**
  88. * The depth map generated using the internal camera; a location beyond a
  89. * pixel's depth is in shadow. Computed internally during rendering.
  90. *
  91. * @type {?RenderTarget}
  92. * @default null
  93. */
  94. this.map = null;
  95. /**
  96. * The distribution map generated using the internal camera; an occlusion is
  97. * calculated based on the distribution of depths. Computed internally during
  98. * rendering.
  99. *
  100. * @type {?RenderTarget}
  101. * @default null
  102. */
  103. this.mapPass = null;
  104. /**
  105. * Model to shadow camera space, to compute location and depth in shadow map.
  106. * This is computed internally during rendering.
  107. *
  108. * @type {Matrix4}
  109. */
  110. this.matrix = new Matrix4();
  111. /**
  112. * Enables automatic updates of the light's shadow. If you do not require dynamic
  113. * lighting / shadows, you may set this to `false`.
  114. *
  115. * @type {boolean}
  116. * @default true
  117. */
  118. this.autoUpdate = true;
  119. /**
  120. * When set to `true`, shadow maps will be updated in the next `render` call.
  121. * If you have set {@link LightShadow#autoUpdate} to `false`, you will need to
  122. * set this property to `true` and then make a render call to update the light's shadow.
  123. *
  124. * @type {boolean}
  125. * @default false
  126. */
  127. this.needsUpdate = false;
  128. this._frustum = new Frustum();
  129. this._frameExtents = new Vector2( 1, 1 );
  130. this._viewportCount = 1;
  131. this._viewports = [
  132. new Vector4( 0, 0, 1, 1 )
  133. ];
  134. }
  135. /**
  136. * Used internally by the renderer to get the number of viewports that need
  137. * to be rendered for this shadow.
  138. *
  139. * @return {number} The viewport count.
  140. */
  141. getViewportCount() {
  142. return this._viewportCount;
  143. }
  144. /**
  145. * Gets the shadow cameras frustum. Used internally by the renderer to cull objects.
  146. *
  147. * @return {Frustum} The shadow camera frustum.
  148. */
  149. getFrustum() {
  150. return this._frustum;
  151. }
  152. /**
  153. * Update the matrices for the camera and shadow, used internally by the renderer.
  154. *
  155. * @param {Light} light - The light for which the shadow is being rendered.
  156. */
  157. updateMatrices( light ) {
  158. const shadowCamera = this.camera;
  159. const shadowMatrix = this.matrix;
  160. _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
  161. shadowCamera.position.copy( _lightPositionWorld );
  162. _lookTarget.setFromMatrixPosition( light.target.matrixWorld );
  163. shadowCamera.lookAt( _lookTarget );
  164. shadowCamera.updateMatrixWorld();
  165. _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
  166. this._frustum.setFromProjectionMatrix( _projScreenMatrix );
  167. shadowMatrix.set(
  168. 0.5, 0.0, 0.0, 0.5,
  169. 0.0, 0.5, 0.0, 0.5,
  170. 0.0, 0.0, 0.5, 0.5,
  171. 0.0, 0.0, 0.0, 1.0
  172. );
  173. shadowMatrix.multiply( _projScreenMatrix );
  174. }
  175. /**
  176. * Returns a viewport definition for the given viewport index.
  177. *
  178. * @param {number} viewportIndex - The viewport index.
  179. * @return {Vector4} The viewport.
  180. */
  181. getViewport( viewportIndex ) {
  182. return this._viewports[ viewportIndex ];
  183. }
  184. /**
  185. * Returns the frame extends.
  186. *
  187. * @return {Vector2} The frame extends.
  188. */
  189. getFrameExtents() {
  190. return this._frameExtents;
  191. }
  192. /**
  193. * Frees the GPU-related resources allocated by this instance. Call this
  194. * method whenever this instance is no longer used in your app.
  195. */
  196. dispose() {
  197. if ( this.map ) {
  198. this.map.dispose();
  199. }
  200. if ( this.mapPass ) {
  201. this.mapPass.dispose();
  202. }
  203. }
  204. /**
  205. * Copies the values of the given light shadow instance to this instance.
  206. *
  207. * @param {LightShadow} source - The light shadow to copy.
  208. * @return {LightShadow} A reference to this light shadow instance.
  209. */
  210. copy( source ) {
  211. this.camera = source.camera.clone();
  212. this.intensity = source.intensity;
  213. this.bias = source.bias;
  214. this.radius = source.radius;
  215. this.mapSize.copy( source.mapSize );
  216. return this;
  217. }
  218. /**
  219. * Returns a new light shadow instance with copied values from this instance.
  220. *
  221. * @return {LightShadow} A clone of this instance.
  222. */
  223. clone() {
  224. return new this.constructor().copy( this );
  225. }
  226. /**
  227. * Serializes the light shadow into JSON.
  228. *
  229. * @return {Object} A JSON object representing the serialized light shadow.
  230. * @see {@link ObjectLoader#parse}
  231. */
  232. toJSON() {
  233. const object = {};
  234. if ( this.intensity !== 1 ) object.intensity = this.intensity;
  235. if ( this.bias !== 0 ) object.bias = this.bias;
  236. if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
  237. if ( this.radius !== 1 ) object.radius = this.radius;
  238. if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
  239. object.camera = this.camera.toJSON( false ).object;
  240. delete object.camera.matrix;
  241. return object;
  242. }
  243. }
  244. export { LightShadow };
粤ICP备19079148号