{"version":3,"file":"CSM.cjs","sources":["../../src/csm/CSM.js"],"sourcesContent":["import { Vector2, Vector3, DirectionalLight, MathUtils, ShaderChunk, Matrix4, Box3 } from 'three'\nimport { CSMFrustum } from './CSMFrustum'\nimport { CSMShader } from './CSMShader'\n\nconst _cameraToLightMatrix = new Matrix4()\nconst _lightSpaceFrustum = new CSMFrustum()\nconst _center = new Vector3()\nconst _bbox = new Box3()\nconst _uniformArray = []\nconst _logArray = []\n\nexport class CSM {\n  constructor(data) {\n    data = data || {}\n\n    this.camera = data.camera\n    this.parent = data.parent\n    this.cascades = data.cascades || 3\n    this.maxFar = data.maxFar || 100000\n    this.mode = data.mode || 'practical'\n    this.shadowMapSize = data.shadowMapSize || 2048\n    this.shadowBias = data.shadowBias || 0.000001\n    this.lightDirection = data.lightDirection || new Vector3(1, -1, 1).normalize()\n    this.lightIntensity = data.lightIntensity || 1\n    this.lightNear = data.lightNear || 1\n    this.lightFar = data.lightFar || 2000\n    this.lightMargin = data.lightMargin || 200\n    this.customSplitsCallback = data.customSplitsCallback\n    this.fade = false\n    this.mainFrustum = new CSMFrustum()\n    this.frustums = []\n    this.breaks = []\n\n    this.lights = []\n    this.shaders = new Map()\n\n    this.createLights()\n    this.updateFrustums()\n    this.injectInclude()\n  }\n\n  createLights() {\n    for (let i = 0; i < this.cascades; i++) {\n      const light = new DirectionalLight(0xffffff, this.lightIntensity)\n      light.castShadow = true\n      light.shadow.mapSize.width = this.shadowMapSize\n      light.shadow.mapSize.height = this.shadowMapSize\n\n      light.shadow.camera.near = this.lightNear\n      light.shadow.camera.far = this.lightFar\n      light.shadow.bias = this.shadowBias\n\n      this.parent.add(light)\n      this.parent.add(light.target)\n      this.lights.push(light)\n    }\n  }\n\n  initCascades() {\n    const camera = this.camera\n    camera.updateProjectionMatrix()\n    this.mainFrustum.setFromProjectionMatrix(camera.projectionMatrix, this.maxFar)\n    this.mainFrustum.split(this.breaks, this.frustums)\n  }\n\n  updateShadowBounds() {\n    const frustums = this.frustums\n    for (let i = 0; i < frustums.length; i++) {\n      const light = this.lights[i]\n      const shadowCam = light.shadow.camera\n      const frustum = this.frustums[i]\n\n      // Get the two points that represent that furthest points on the frustum assuming\n      // that's either the diagonal across the far plane or the diagonal across the whole\n      // frustum itself.\n      const nearVerts = frustum.vertices.near\n      const farVerts = frustum.vertices.far\n      const point1 = farVerts[0]\n      let point2\n      if (point1.distanceTo(farVerts[2]) > point1.distanceTo(nearVerts[2])) {\n        point2 = farVerts[2]\n      } else {\n        point2 = nearVerts[2]\n      }\n\n      let squaredBBWidth = point1.distanceTo(point2)\n      if (this.fade) {\n        // expand the shadow extents by the fade margin if fade is enabled.\n        const camera = this.camera\n        const far = Math.max(camera.far, this.maxFar)\n        const linearDepth = frustum.vertices.far[0].z / (far - camera.near)\n        const margin = 0.25 * Math.pow(linearDepth, 2.0) * (far - camera.near)\n\n        squaredBBWidth += margin\n      }\n\n      shadowCam.left = -squaredBBWidth / 2\n      shadowCam.right = squaredBBWidth / 2\n      shadowCam.top = squaredBBWidth / 2\n      shadowCam.bottom = -squaredBBWidth / 2\n      shadowCam.updateProjectionMatrix()\n    }\n  }\n\n  getBreaks() {\n    const camera = this.camera\n    const far = Math.min(camera.far, this.maxFar)\n    this.breaks.length = 0\n\n    switch (this.mode) {\n      case 'uniform':\n        uniformSplit(this.cascades, camera.near, far, this.breaks)\n        break\n      case 'logarithmic':\n        logarithmicSplit(this.cascades, camera.near, far, this.breaks)\n        break\n      case 'practical':\n        practicalSplit(this.cascades, camera.near, far, 0.5, this.breaks)\n        break\n      case 'custom':\n        if (this.customSplitsCallback === undefined) console.error('CSM: Custom split scheme callback not defined.')\n        this.customSplitsCallback(this.cascades, camera.near, far, this.breaks)\n        break\n    }\n\n    function uniformSplit(amount, near, far, target) {\n      for (let i = 1; i < amount; i++) {\n        target.push((near + ((far - near) * i) / amount) / far)\n      }\n\n      target.push(1)\n    }\n\n    function logarithmicSplit(amount, near, far, target) {\n      for (let i = 1; i < amount; i++) {\n        target.push((near * (far / near) ** (i / amount)) / far)\n      }\n\n      target.push(1)\n    }\n\n    function practicalSplit(amount, near, far, lambda, target) {\n      _uniformArray.length = 0\n      _logArray.length = 0\n      logarithmicSplit(amount, near, far, _logArray)\n      uniformSplit(amount, near, far, _uniformArray)\n\n      for (let i = 1; i < amount; i++) {\n        target.push(MathUtils.lerp(_uniformArray[i - 1], _logArray[i - 1], lambda))\n      }\n\n      target.push(1)\n    }\n  }\n\n  update() {\n    const camera = this.camera\n    const frustums = this.frustums\n    for (let i = 0; i < frustums.length; i++) {\n      const light = this.lights[i]\n      const shadowCam = light.shadow.camera\n      const texelWidth = (shadowCam.right - shadowCam.left) / this.shadowMapSize\n      const texelHeight = (shadowCam.top - shadowCam.bottom) / this.shadowMapSize\n      light.shadow.camera.updateMatrixWorld(true)\n      _cameraToLightMatrix.multiplyMatrices(light.shadow.camera.matrixWorldInverse, camera.matrixWorld)\n      frustums[i].toSpace(_cameraToLightMatrix, _lightSpaceFrustum)\n\n      const nearVerts = _lightSpaceFrustum.vertices.near\n      const farVerts = _lightSpaceFrustum.vertices.far\n      _bbox.makeEmpty()\n      for (let j = 0; j < 4; j++) {\n        _bbox.expandByPoint(nearVerts[j])\n        _bbox.expandByPoint(farVerts[j])\n      }\n\n      _bbox.getCenter(_center)\n      _center.z = _bbox.max.z + this.lightMargin\n      _center.x = Math.floor(_center.x / texelWidth) * texelWidth\n      _center.y = Math.floor(_center.y / texelHeight) * texelHeight\n      _center.applyMatrix4(light.shadow.camera.matrixWorld)\n\n      light.position.copy(_center)\n      light.target.position.copy(_center)\n\n      light.target.position.x += this.lightDirection.x\n      light.target.position.y += this.lightDirection.y\n      light.target.position.z += this.lightDirection.z\n    }\n  }\n\n  injectInclude() {\n    ShaderChunk.lights_fragment_begin = CSMShader.lights_fragment_begin\n    ShaderChunk.lights_pars_begin = CSMShader.lights_pars_begin\n  }\n\n  setupMaterial(material) {\n    material.defines = material.defines || {}\n    material.defines.USE_CSM = 1\n    material.defines.CSM_CASCADES = this.cascades\n\n    if (this.fade) {\n      material.defines.CSM_FADE = ''\n    }\n\n    const breaksVec2 = []\n    const scope = this\n    const shaders = this.shaders\n\n    material.onBeforeCompile = function (shader) {\n      const far = Math.min(scope.camera.far, scope.maxFar)\n      scope.getExtendedBreaks(breaksVec2)\n\n      shader.uniforms.CSM_cascades = { value: breaksVec2 }\n      shader.uniforms.cameraNear = { value: scope.camera.near }\n      shader.uniforms.shadowFar = { value: far }\n\n      shaders.set(material, shader)\n    }\n\n    shaders.set(material, null)\n  }\n\n  updateUniforms() {\n    const far = Math.min(this.camera.far, this.maxFar)\n    const shaders = this.shaders\n\n    shaders.forEach(function (shader, material) {\n      if (shader !== null) {\n        const uniforms = shader.uniforms\n        this.getExtendedBreaks(uniforms.CSM_cascades.value)\n        uniforms.cameraNear.value = this.camera.near\n        uniforms.shadowFar.value = far\n      }\n\n      if (!this.fade && 'CSM_FADE' in material.defines) {\n        delete material.defines.CSM_FADE\n        material.needsUpdate = true\n      } else if (this.fade && !('CSM_FADE' in material.defines)) {\n        material.defines.CSM_FADE = ''\n        material.needsUpdate = true\n      }\n    }, this)\n  }\n\n  getExtendedBreaks(target) {\n    while (target.length < this.breaks.length) {\n      target.push(new Vector2())\n    }\n\n    target.length = this.breaks.length\n\n    for (let i = 0; i < this.cascades; i++) {\n      const amount = this.breaks[i]\n      const prev = this.breaks[i - 1] || 0\n      target[i].x = prev\n      target[i].y = amount\n    }\n  }\n\n  updateFrustums() {\n    this.getBreaks()\n    this.initCascades()\n    this.updateShadowBounds()\n    this.updateUniforms()\n  }\n\n  remove() {\n    for (let i = 0; i < this.lights.length; i++) {\n      this.parent.remove(this.lights[i])\n    }\n  }\n\n  dispose() {\n    const shaders = this.shaders\n    shaders.forEach(function (shader, material) {\n      delete material.onBeforeCompile\n      delete material.defines.USE_CSM\n      delete material.defines.CSM_CASCADES\n      delete material.defines.CSM_FADE\n\n      if (shader !== null) {\n        delete shader.uniforms.CSM_cascades\n        delete shader.uniforms.cameraNear\n        delete shader.uniforms.shadowFar\n      }\n\n      material.needsUpdate = true\n    })\n    shaders.clear()\n  }\n}\n"],"names":["Matrix4","CSMFrustum","Vector3","Box3","DirectionalLight","far","MathUtils","ShaderChunk","CSMShader","Vector2"],"mappings":"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"}