"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const postprocessing = require("postprocessing");
const THREE = require("three");
const compat = require("../../compat.cjs");
const boxBlur = (
  /* glsl */
  `
  uniform float blur;
  uniform float blurSharpness;
  uniform int blurKernel;

  vec3 denoise(
    vec3 center,
    sampler2D tex,
    vec2 uv,
    vec2 invTexSize,
    float blur,
    float blurSharpness,
    int blurKernel
  ) {
    vec3 color, col;
    float total, weight;

    for (int x = -blurKernel; x <= blurKernel; x++) {
      for (int y=-blurKernel; y<=blurKernel; y++) {
        col = textureLod(tex, uv + vec2(x,y) * invTexSize, 0.0).rgb;
        weight = 1.0-abs(dot(col - center, vec3(0.25)));
        weight = pow(weight, blurSharpness);
        color += col * weight;
        total += weight;
      }
    }

    return color / total;
  }
`
);
const finalSSRShader = (
  /* glsl */
  `
  #define MODE_DEFAULT 0
  #define MODE_REFLECTIONS 1
  #define MODE_RAW_REFLECTION 2
  #define MODE_BLURRED_REFLECTIONS 3
  #define MODE_INPUT 4
  #define MODE_BLUR_MIX 5
  #define FLOAT_EPSILON 0.00001
  // uniform sampler2D inputTexture;
  uniform sampler2D reflectionsTexture;
  // uniform float samples;

  ${boxBlur}

  void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
    vec4 reflectionsTexel=texture2D(reflectionsTexture, vUv);
    ivec2 size = textureSize(reflectionsTexture, 0);
    vec2 invTexSize= 1.0 / vec2(size.x, size.y);
    vec3 reflectionClr = reflectionsTexel.xyz;
    if (blur > FLOAT_EPSILON) {
      vec3 blurredReflectionsColor = denoise(
        reflectionsTexel.rgb,
        reflectionsTexture,
        vUv,
        invTexSize,
        blur,
        blurSharpness,
        blurKernel
      );
      reflectionClr = mix(reflectionClr, blurredReflectionsColor.rgb, blur);
    }

    #if RENDER_MODE == MODE_DEFAULT
      outputColor = vec4(inputColor.rgb+reflectionClr, 1.0);
    #endif
    #if RENDER_MODE == MODE_REFLECTIONS
      outputColor = vec4(reflectionClr, 1.0);
    #endif
    #if RENDER_MODE == MODE_RAW_REFLECTION
      outputColor = vec4(reflectionsTexel.xyz, 1.0);
    #endif
    #if RENDER_MODE == MODE_BLURRED_REFLECTIONS
      outputColor = vec4(blurredReflectionsTexel.xyz, 1.0);
    #endif
    #if RENDER_MODE == MODE_INPUT
      outputColor = vec4(inputColor.xyz, 1.0);
    #endif
    #if RENDER_MODE == MODE_BLUR_MIX
      outputColor = vec4(vec3(blur), 1.0);
    #endif
  }
`
);
const helperFunctions = (
  /* glsl */
  `
  vec3 getViewPosition(const float depth) {
    float clipW= _projectionMatrix[2][3] * depth + _projectionMatrix[3][3];
    vec4 clipPosition = vec4((vec3(vUv, depth) - 0.5) * 2.0, 1.0);
    clipPosition *= clipW;
    return(_inverseProjectionMatrix * clipPosition).xyz;
  }

  float getViewZ(const in float depth) {
    #ifdef PERSPECTIVE_CAMERA
      return perspectiveDepthToViewZ(depth, cameraNear, cameraFar);
    #else
      return orthographicDepthToViewZ(depth, cameraNear, cameraFar);
    #endif
  }

  vec3 screenSpaceToWorldSpace(const vec2 uv,const float depth){
    vec4 ndc = vec4((uv.x - 0.5) * 2.0,(uv.y - 0.5)* 2.0, (depth - 0.5) * 2.0, 1.0);
    vec4 clip= _inverseProjectionMatrix*ndc;
    vec4 view = cameraMatrixWorld * (clip / clip.w);
    return view.xyz;
  }

  #define Scale (vec3(0.8, 0.8, 0.8))
  #define K (19.19)

  vec3 hash(vec3 a) {
    a = fract(a * Scale);
    a += dot(a, a.yxz + K);
    return fract((a.xxy + a.yxx) * a.zyx);
  }

  float fresnel_dielectric_cos(float cosi, float eta){
    float c = abs(cosi);
    float g = eta * eta - 1.0 +  c* c;
    float result;

    if (g > 0.0){
      g = sqrt(g);
      float A = (g - c) / (g + c);
      float B = (c* (g + c) - 1.0) / (c * (g - c) + 1.0);
      result = 0.5 * A * A * (1.0 + B * B);
    } else {
      result = 1.0;
    }
    
    return result;
  }

  float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta){
    float cosine = dot(Incoming, Normal);
    return min(1.0, 5.0 * fresnel_dielectric_cos(cosine, eta));
  }
`
);
const trCompose = (
  /* glsl */
  `
  #define INV_EULER 0.36787944117144233

  alpha = velocityDisocclusion < FLOAT_EPSILON ? (alpha + 0.0075) : 0.0;
  alpha = clamp(alpha, 0.0, 1.0);
  bool needsBlur = !didReproject || velocityDisocclusion > 0.5;

  #ifdef boxBlur
    if (needsBlur) inputColor = boxBlurredColor;
  #endif

  if (alpha == 1.0) {
    outputColor = accumulatedColor;
  } else {
    float m = mix(alpha, 1.0, blend);
    if (needsBlur) m = 0.0;
    outputColor = accumulatedColor * m + inputColor * (1.0 - m);
  }
`
);
class MRTMaterial extends THREE.ShaderMaterial {
  constructor() {
    super({
      type: "MRTMaterial",
      defines: {
        USE_UV: "",
        TEMPORAL_RESOLVE: ""
      },
      uniforms: {
        opacity: new THREE.Uniform(1),
        normalMap: new THREE.Uniform(null),
        normalScale: new THREE.Uniform(new THREE.Vector2(1, 1)),
        uvTransform: new THREE.Uniform(new THREE.Matrix3()),
        roughness: new THREE.Uniform(1),
        roughnessMap: new THREE.Uniform(null)
      },
      vertexShader: (
        /* glsl */
        `
        #ifdef USE_MRT
          varying vec2 vHighPrecisionZW;
        #endif
        #define NORMAL
        #if defined(FLAT_SHADED) || defined(USE_BUMPMAP) || defined(TANGENTSPACE_NORMALMAP)
          varying vec3 vViewPosition;
        #endif
        #include <common>
        #include <uv_pars_vertex>
        #include <displacementmap_pars_vertex>
        #include <normal_pars_vertex>
        #include <morphtarget_pars_vertex>
        #include <skinning_pars_vertex>
        #include <logdepthbuf_pars_vertex>
        #include <clipping_planes_pars_vertex>
        #ifdef USE_UV
          ${THREE.REVISION.replace(/\D+/g, "") >= 151 ? "uniform mat3 uvTransform;" : ""}
        #endif
        void main() {
          #include <uv_vertex>
          #include <beginnormal_vertex>
          #include <morphnormal_vertex>
          #include <skinbase_vertex>
          #include <skinnormal_vertex>
          #include <defaultnormal_vertex>
          #include <normal_vertex>
          #include <begin_vertex>
          #include <morphtarget_vertex>
          #include <skinning_vertex>
          #include <displacementmap_vertex>
          #include <project_vertex>
          #include <logdepthbuf_vertex>
          #include <clipping_planes_vertex>
          #if defined(FLAT_SHADED) || defined(USE_BUMPMAP) || defined(TANGENTSPACE_NORMALMAP)
            vViewPosition = -mvPosition.xyz;
          #endif
          #ifdef USE_MRT
            vHighPrecisionZW = gl_Position.zw;
          #endif
          #ifdef USE_UV
            vUv = (uvTransform * vec3(uv, 1)).xy;
          #endif
        }
      `
      ),
      fragmentShader: (
        /* glsl */
        `
        #define NORMAL
        #if defined(FLAT_SHADED) || defined(USE_BUMPMAP) || defined(TANGENTSPACE_NORMALMAP)
          varying vec3 vViewPosition;
        #endif
        #include <packing>
        #include <uv_pars_fragment>
        #include <normal_pars_fragment>
        #include <bumpmap_pars_fragment>
        #include <normalmap_pars_fragment>
        #include <logdepthbuf_pars_fragment>
        #include <clipping_planes_pars_fragment>
        #include <roughnessmap_pars_fragment>

        #ifdef USE_MRT
          layout(location = 0) out vec4 gNormal;
          layout(location = 1) out vec4 gDepth;
          varying vec2 vHighPrecisionZW;
        #endif
        uniform float roughness;
        void main() {
          #include <clipping_planes_fragment>
          #include <logdepthbuf_fragment>
          #include <normal_fragment_begin>
          #include <normal_fragment_maps>

          float roughnessFactor = roughness;

          if (roughness > 10.0e9){
            roughnessFactor = 1.;
          } else {
            #ifdef useRoughnessMap
              vec4 texelRoughness = texture2D(roughnessMap, vUv);
              // reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture
              roughnessFactor *= texelRoughness.g;
            #endif
          }

          vec3 normalColor = packNormalToRGB(normal);
          #ifdef USE_MRT
            float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;
            vec4 depthColor = packDepthToRGBA(fragCoordZ);
            gNormal = vec4(normalColor, roughnessFactor);
            gDepth = depthColor;
          #else
            gl_FragColor = vec4(normalColor, roughnessFactor);
          #endif
        }
      `
      ),
      toneMapped: false
    });
    this.normalMapType = THREE.TangentSpaceNormalMap;
    this.normalScale = new THREE.Vector2(1, 1);
    Object.defineProperty(this, "glslVersion", {
      get() {
        return "USE_MRT" in this.defines ? THREE.GLSL3 : null;
      },
      set(_) {
      }
    });
  }
}
const vertexShader = (
  /* glsl */
  `
  varying vec2 vUv;

  void main() {
    vUv = position.xy * 0.5 + 0.5;
    gl_Position = vec4(position.xy, 1.0, 1.0);
  }
`
);
const fragmentShader = (
  /* glsl */
  `
  varying vec2 vUv;
  uniform sampler2D inputTexture;
  uniform sampler2D accumulatedTexture;
  uniform sampler2D normalTexture;
  uniform sampler2D depthTexture;
  uniform sampler2D envMap;
  uniform mat4 _projectionMatrix;
  uniform mat4 _inverseProjectionMatrix;
  uniform mat4 cameraMatrixWorld;
  uniform float cameraNear;
  uniform float cameraFar;
  uniform float rayDistance;
  uniform float intensity;
  uniform float maxDepthDifference;
  uniform float roughnessFade;
  uniform float maxRoughness;
  uniform float fade;
  uniform float thickness;
  uniform float ior;
  uniform float samples;
  uniform float jitter;
  uniform float jitterRoughness;

  #define INVALID_RAY_COORDS vec2(-1.0);

  #define EARLY_OUT_COLOR vec4(0.0, 0.0, 0.0, 1.0)
  #define FLOAT_EPSILON 0.00001
  float nearMinusFar;
  float nearMulFar;
  float farMinusNear;

  #include <packing>

  ${helperFunctions}

  vec2 RayMarch(vec3 dir, inout vec3 hitPos, inout float rayHitDepthDifference);
  vec2 BinarySearch(in vec3 dir, inout vec3 hitPos, inout float rayHitDepthDifference);
  float fastGetViewZ(const in float depth);
  vec3 getIBLRadiance(const in vec3 viewDir, const in vec3 normal, const in float roughness);

  void main() {
    vec4 depthTexel = textureLod(depthTexture, vUv, 0.0);

    if (dot(depthTexel.rgb, depthTexel.rgb) < FLOAT_EPSILON) {
      gl_FragColor = EARLY_OUT_COLOR;
      return;
    }

    float unpackedDepth = unpackRGBAToDepth(depthTexel);
    vec4 normalTexel = textureLod(normalTexture, vUv, 0.0);
    float roughness = normalTexel.a;
    float specular = 1.0 - roughness;

    nearMinusFar = cameraNear - cameraFar;
    nearMulFar = cameraNear * cameraFar;
    farMinusNear = cameraFar - cameraNear;

    normalTexel.rgb = unpackRGBToNormal(normalTexel.rgb);

    float depth = fastGetViewZ(unpackedDepth);
    vec3 viewPos = getViewPosition(depth);
    vec3 viewDir = normalize(viewPos);
    vec3 viewNormal = normalTexel.xyz;
    vec3 worldPos = screenSpaceToWorldSpace(vUv, unpackedDepth);

    vec3 jitt=vec3(0.0);
    if (jitterRoughness != 0.0 || jitter!=0.0){
      vec3 randomJitter = hash(50.0 * samples * worldPos) - 0.5;
      float spread= ((2.0 - specular) + roughness * jitterRoughness);
      float jitterMix = jitter * 0.25 + jitterRoughness * roughness;
      if (jitterMix > 1.0) jitterMix = 1.0;
      jitt = mix(vec3(0.0), randomJitter * spread, jitterMix);
    }
    
    viewNormal += jitt;
    float fresnelFactor = fresnel_dielectric(viewDir, viewNormal, ior);
    vec3 iblRadiance = getIBLRadiance(-viewDir, viewNormal, 0.0) * fresnelFactor;
    float lastFrameAlpha = textureLod(accumulatedTexture, vUv, 0.0).a;
    if (roughness > maxRoughness || (roughness > 1.0 - FLOAT_EPSILON && roughnessFade > 1.0 - FLOAT_EPSILON)) {
      gl_FragColor=vec4(iblRadiance,lastFrameAlpha);
      return;
    }
    
    vec3 reflected = reflect(viewDir, viewNormal);
    vec3 rayDir = reflected *- viewPos.z;
    vec3 hitPos = viewPos;
    float rayHitDepthDifference;
    vec2 coords = RayMarch(rayDir, hitPos, rayHitDepthDifference);
    if (coords.x == -1.0){
      gl_FragColor=vec4(iblRadiance, lastFrameAlpha);
      return;
    }
    
    vec4 SSRTexel = textureLod(inputTexture, coords.xy, 0.0);
    vec4 SSRTexelReflected = textureLod(accumulatedTexture, coords.xy, 0.0);
    vec3 SSR = SSRTexel.rgb + SSRTexelReflected.rgb;
    float roughnessFactor = mix(specular, 1.0, max(0.0, 1.0 - roughnessFade));
    vec2 coordsNDC = (coords.xy * 2.0 - 1.0);
    float screenFade = 0.1;
    float maxDimension = min(1.0, max(abs(coordsNDC.x), abs(coordsNDC.y)));
    float reflectionIntensity = 1.0 - (max(0.0, maxDimension - screenFade) / (1.0 - screenFade));
    reflectionIntensity = max(0.0, reflectionIntensity);
    vec3 finalSSR = mix(iblRadiance, SSR, reflectionIntensity) * roughnessFactor;

    if (fade != 0.0) {
      vec3 hitWorldPos = screenSpaceToWorldSpace(coords, rayHitDepthDifference);
      float reflectionDistance = distance(hitWorldPos, worldPos) + 1.0;
      float opacity = 1.0 / (reflectionDistance * fade * 0.1);
      if(opacity > 1.0) opacity=1.0;
      finalSSR *= opacity;
    }

    finalSSR *= fresnelFactor * intensity;
    finalSSR = min(vec3(1.0), finalSSR);
    float alpha = hitPos.z == 1.0 ? 1.0 : SSRTexelReflected.a;
    alpha = min(lastFrameAlpha, alpha);
    gl_FragColor = vec4(finalSSR, alpha);
  }

  vec2 RayMarch(vec3 dir, inout vec3 hitPos, inout float rayHitDepthDifference) {
    dir=normalize(dir);
    dir *= rayDistance / float(steps);
    float depth;
    vec4 projectedCoord;
    vec4 lastProjectedCoord;
    float unpackedDepth;
    vec4 depthTexel;

    for (int i = 0; i < steps; i++) {
      hitPos += dir;
      projectedCoord = _projectionMatrix * vec4(hitPos, 1.0);
      projectedCoord.xy /= projectedCoord.w;
      projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;

      #ifndef missedRays
        if (
          projectedCoord.x < 0.0 ||
          projectedCoord.x > 1.0 ||
          projectedCoord.y < 0.0 ||
          projectedCoord.y > 1.0
        ) {
          return INVALID_RAY_COORDS;
        }
      #endif

      depthTexel = textureLod(depthTexture, projectedCoord.xy, 0.0);
      unpackedDepth = unpackRGBAToDepth(depthTexel);
      depth = fastGetViewZ(unpackedDepth);
      rayHitDepthDifference = depth - hitPos.z;

      if (rayHitDepthDifference >= 0.0 && rayHitDepthDifference < thickness){
        #if refineSteps == 0
          if (dot(depthTexel.rgb, depthTexel.rgb) < FLOAT_EPSILON) return INVALID_RAY_COORDS;
        #else
          return BinarySearch(dir, hitPos, rayHitDepthDifference);
        #endif
      }

      #ifndef missedRays
        if (hitPos.z > 0.0) return INVALID_RAY_COORDS;
      #endif

      lastProjectedCoord = projectedCoord;
    }
    
    hitPos.z = 1.0;

    #ifndef missedRays
      return INVALID_RAY_COORDS;
    #endif

    rayHitDepthDifference = unpackedDepth;

    return projectedCoord.xy;
  }

  vec2 BinarySearch(in vec3 dir, inout vec3 hitPos, inout float rayHitDepthDifference) {
    float depth;
    vec4 projectedCoord;
    vec2 lastMinProjectedCoordXY;
    float unpackedDepth;
    vec4 depthTexel;

    for (int i = 0; i < refineSteps; i++){
      projectedCoord = _projectionMatrix * vec4(hitPos, 1.0);
      projectedCoord.xy /= projectedCoord.w;
      projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
      depthTexel = textureLod(depthTexture, projectedCoord.xy, 0.0);
      unpackedDepth = unpackRGBAToDepth(depthTexel);
      depth = fastGetViewZ(unpackedDepth);
      rayHitDepthDifference = depth - hitPos.z;
      dir *= 0.5;

      if (rayHitDepthDifference > 0.0) {
        hitPos -= dir;
      } else {
        hitPos += dir;
      }
    }
    
    if (dot(depthTexel.rgb, depthTexel.rgb) < FLOAT_EPSILON) return INVALID_RAY_COORDS;
    if (abs(rayHitDepthDifference) > maxDepthDifference) return INVALID_RAY_COORDS;

    projectedCoord = _projectionMatrix*vec4(hitPos, 1.0);
    projectedCoord.xy /= projectedCoord.w;
    projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
    rayHitDepthDifference = unpackedDepth;
    return projectedCoord.xy;
  }

  float fastGetViewZ(const in float depth){
    #ifdef PERSPECTIVE_CAMERA
      return nearMulFar / (farMinusNear * depth - cameraFar);
    #else
      return depth * nearMinusFar - cameraNear;
    #endif
  }

  #include <common>
  #include <cube_uv_reflection_fragment>

  vec3 getIBLRadiance(const in vec3 viewDir, const in vec3 normal, const in float roughness){
    #if defined(ENVMAP_TYPE_CUBE_UV)
      vec3 reflectVec = reflect(-viewDir, normal);
      reflectVec = normalize(mix(reflectVec, normal,roughness * roughness));
      reflectVec = inverseTransformDirection(reflectVec, viewMatrix);
      vec4 envMapColor = textureCubeUV(envMap, reflectVec, roughness);
      return envMapColor.rgb * intensity;
    #else
      return vec3(0.0);
    #endif
  }
`
);
class ReflectionsMaterial extends THREE.ShaderMaterial {
  constructor() {
    super({
      type: "ReflectionsMaterial",
      uniforms: {
        inputTexture: new THREE.Uniform(null),
        accumulatedTexture: new THREE.Uniform(null),
        normalTexture: new THREE.Uniform(null),
        depthTexture: new THREE.Uniform(null),
        _projectionMatrix: new THREE.Uniform(new THREE.Matrix4()),
        _inverseProjectionMatrix: new THREE.Uniform(new THREE.Matrix4()),
        cameraMatrixWorld: new THREE.Uniform(new THREE.Matrix4()),
        cameraNear: new THREE.Uniform(0),
        cameraFar: new THREE.Uniform(0),
        rayDistance: new THREE.Uniform(0),
        intensity: new THREE.Uniform(0),
        roughnessFade: new THREE.Uniform(0),
        fade: new THREE.Uniform(0),
        thickness: new THREE.Uniform(0),
        ior: new THREE.Uniform(0),
        maxDepthDifference: new THREE.Uniform(0),
        jitter: new THREE.Uniform(0),
        jitterRoughness: new THREE.Uniform(0),
        maxRoughness: new THREE.Uniform(0),
        samples: new THREE.Uniform(0),
        envMap: new THREE.Uniform(null),
        envMapPosition: new THREE.Uniform(new THREE.Vector3()),
        envMapSize: new THREE.Uniform(new THREE.Vector3()),
        viewMatrix: new THREE.Uniform(new THREE.Matrix4())
      },
      defines: {
        steps: 20,
        refineSteps: 5,
        CUBEUV_TEXEL_WIDTH: 0,
        CUBEUV_TEXEL_HEIGHT: 0,
        CUBEUV_MAX_MIP: 0,
        vWorldPosition: "worldPos"
      },
      fragmentShader,
      vertexShader,
      toneMapped: false,
      depthWrite: false,
      depthTest: false
    });
  }
}
const getVisibleChildren = (object) => {
  const queue = [object];
  const objects = [];
  while (queue.length !== 0) {
    const mesh = queue.shift();
    if (mesh.material)
      objects.push(mesh);
    for (const c of mesh.children) {
      if (c.visible)
        queue.push(c);
    }
  }
  return objects;
};
const generateCubeUVSize = (parameters) => {
  const imageHeight = parameters.envMapCubeUVHeight;
  if (imageHeight === null)
    return null;
  const maxMip = Math.log2(imageHeight) - 2;
  const texelHeight = 1 / imageHeight;
  const texelWidth = 1 / (3 * Math.max(Math.pow(2, maxMip), 7 * 16));
  return {
    texelWidth,
    texelHeight,
    maxMip
  };
};
const setupEnvMap = (reflectionsMaterial, envMap, envMapCubeUVHeight) => {
  reflectionsMaterial.uniforms.envMap.value = envMap;
  const envMapCubeUVSize = generateCubeUVSize({
    envMapCubeUVHeight
  });
  reflectionsMaterial.defines.ENVMAP_TYPE_CUBE_UV = "";
  reflectionsMaterial.defines.CUBEUV_TEXEL_WIDTH = envMapCubeUVSize.texelWidth;
  reflectionsMaterial.defines.CUBEUV_TEXEL_HEIGHT = envMapCubeUVSize.texelHeight;
  reflectionsMaterial.defines.CUBEUV_MAX_MIP = envMapCubeUVSize.maxMip + ".0";
  reflectionsMaterial.needsUpdate = true;
};
const isWebGL2Available = () => {
  try {
    const canvas = document.createElement("canvas");
    return !!(window.WebGL2RenderingContext && canvas.getContext("webgl2"));
  } catch (e) {
    return false;
  }
};
class ReflectionsPass extends postprocessing.Pass {
  constructor(ssrEffect, options = {}) {
    super("ReflectionsPass");
    this.ssrEffect = void 0;
    this.cachedMaterials = /* @__PURE__ */ new WeakMap();
    this.USE_MRT = false;
    this.webgl1DepthPass = null;
    this.visibleMeshes = [];
    this.ssrEffect = ssrEffect;
    this._scene = ssrEffect._scene;
    this._camera = ssrEffect._camera;
    this.fullscreenMaterial = new ReflectionsMaterial();
    if (ssrEffect._camera.isPerspectiveCamera)
      this.fullscreenMaterial.defines.PERSPECTIVE_CAMERA = "";
    const width = options.width || typeof window !== "undefined" ? window.innerWidth : 2e3;
    const height = options.height || typeof window !== "undefined" ? window.innerHeight : 1e3;
    this.renderTarget = new THREE.WebGLRenderTarget(width, height, {
      minFilter: THREE.LinearFilter,
      magFilter: THREE.LinearFilter,
      type: THREE.HalfFloatType,
      depthBuffer: false
    });
    this.renderPass = new postprocessing.RenderPass(this._scene, this._camera);
    this.USE_MRT = isWebGL2Available();
    if (this.USE_MRT) {
      this.gBuffersRenderTarget = new compat.WebGLMultipleRenderTargets(width, height, 2, {
        minFilter: THREE.LinearFilter,
        magFilter: THREE.LinearFilter
      });
      this.normalTexture = this.gBuffersRenderTarget.texture[0];
      this.depthTexture = this.gBuffersRenderTarget.texture[1];
    } else {
      this.webgl1DepthPass = new postprocessing.DepthPass(this._scene, this._camera);
      this.webgl1DepthPass.renderTarget.minFilter = THREE.LinearFilter;
      this.webgl1DepthPass.renderTarget.magFilter = THREE.LinearFilter;
      this.webgl1DepthPass.renderTarget.texture.minFilter = THREE.LinearFilter;
      this.webgl1DepthPass.renderTarget.texture.magFilter = THREE.LinearFilter;
      this.webgl1DepthPass.setSize(
        typeof window !== "undefined" ? window.innerWidth : 2e3,
        typeof window !== "undefined" ? window.innerHeight : 1e3
      );
      this.gBuffersRenderTarget = new THREE.WebGLRenderTarget(width, height, {
        minFilter: THREE.LinearFilter,
        magFilter: THREE.LinearFilter
      });
      this.normalTexture = this.gBuffersRenderTarget.texture;
      this.depthTexture = this.webgl1DepthPass.texture;
    }
    this.fullscreenMaterial.uniforms.normalTexture.value = this.normalTexture;
    this.fullscreenMaterial.uniforms.depthTexture.value = this.depthTexture;
    this.fullscreenMaterial.uniforms.accumulatedTexture.value = this.ssrEffect.temporalResolvePass.accumulatedTexture;
    this.fullscreenMaterial.uniforms.cameraMatrixWorld.value = this._camera.matrixWorld;
    this.fullscreenMaterial.uniforms._projectionMatrix.value = this._camera.projectionMatrix;
    this.fullscreenMaterial.uniforms._inverseProjectionMatrix.value = this._camera.projectionMatrixInverse;
  }
  setSize(width, height) {
    this.renderTarget.setSize(width * this.ssrEffect.resolutionScale, height * this.ssrEffect.resolutionScale);
    this.gBuffersRenderTarget.setSize(width * this.ssrEffect.resolutionScale, height * this.ssrEffect.resolutionScale);
    this.fullscreenMaterial.uniforms.accumulatedTexture.value = this.ssrEffect.temporalResolvePass.accumulatedTexture;
    this.fullscreenMaterial.needsUpdate = true;
  }
  dispose() {
    this.renderTarget.dispose();
    this.gBuffersRenderTarget.dispose();
    this.renderPass.dispose();
    if (!this.USE_MRT)
      this.webgl1DepthPass.dispose();
    this.fullscreenMaterial.dispose();
    this.normalTexture = null;
    this.depthTexture = null;
    this.velocityTexture = null;
  }
  keepMaterialMapUpdated(mrtMaterial, originalMaterial, prop, define) {
    if (this.ssrEffect[define]) {
      if (originalMaterial[prop] !== mrtMaterial[prop]) {
        mrtMaterial[prop] = originalMaterial[prop];
        mrtMaterial.uniforms[prop].value = originalMaterial[prop];
        if (originalMaterial[prop]) {
          mrtMaterial.defines[define] = "";
        } else {
          delete mrtMaterial.defines[define];
        }
        mrtMaterial.needsUpdate = true;
      }
    } else if (mrtMaterial[prop] !== void 0) {
      mrtMaterial[prop] = void 0;
      mrtMaterial.uniforms[prop].value = void 0;
      delete mrtMaterial.defines[define];
      mrtMaterial.needsUpdate = true;
    }
  }
  setMRTMaterialInScene() {
    this.visibleMeshes = getVisibleChildren(this._scene);
    for (const c of this.visibleMeshes) {
      if (c.material) {
        const originalMaterial = c.material;
        let [cachedOriginalMaterial, mrtMaterial] = this.cachedMaterials.get(c) || [];
        if (originalMaterial !== cachedOriginalMaterial) {
          if (mrtMaterial)
            mrtMaterial.dispose();
          mrtMaterial = new MRTMaterial();
          if (this.USE_MRT)
            mrtMaterial.defines.USE_MRT = "";
          mrtMaterial.normalScale = originalMaterial.normalScale;
          mrtMaterial.uniforms.normalScale.value = originalMaterial.normalScale;
          const map = originalMaterial.map || originalMaterial.normalMap || originalMaterial.roughnessMap || originalMaterial.metalnessMap;
          if (map)
            mrtMaterial.uniforms.uvTransform.value = map.matrix;
          this.cachedMaterials.set(c, [originalMaterial, mrtMaterial]);
        }
        this.keepMaterialMapUpdated(mrtMaterial, originalMaterial, "normalMap", "useNormalMap");
        this.keepMaterialMapUpdated(mrtMaterial, originalMaterial, "roughnessMap", "useRoughnessMap");
        mrtMaterial.uniforms.roughness.value = this.ssrEffect.selection.size === 0 || this.ssrEffect.selection.has(c) ? originalMaterial.roughness || 0 : 1e11;
        c.material = mrtMaterial;
      }
    }
  }
  unsetMRTMaterialInScene() {
    for (const c of this.visibleMeshes) {
      var _c$material;
      if (((_c$material = c.material) == null ? void 0 : _c$material.type) === "MRTMaterial") {
        c.visible = true;
        const [originalMaterial] = this.cachedMaterials.get(c);
        c.material = originalMaterial;
      }
    }
  }
  render(renderer, inputBuffer) {
    this.setMRTMaterialInScene();
    renderer.setRenderTarget(this.gBuffersRenderTarget);
    this.renderPass.render(renderer, this.gBuffersRenderTarget);
    this.unsetMRTMaterialInScene();
    if (!this.USE_MRT)
      this.webgl1DepthPass.renderPass.render(renderer, this.webgl1DepthPass.renderTarget);
    this.fullscreenMaterial.uniforms.inputTexture.value = inputBuffer.texture;
    this.fullscreenMaterial.uniforms.samples.value = this.ssrEffect.temporalResolvePass.samples;
    this.fullscreenMaterial.uniforms.cameraNear.value = this._camera.near;
    this.fullscreenMaterial.uniforms.cameraFar.value = this._camera.far;
    this.fullscreenMaterial.uniforms.viewMatrix.value.copy(this._camera.matrixWorldInverse);
    renderer.setRenderTarget(this.renderTarget);
    renderer.render(this.scene, this.camera);
  }
}
const defaultSSROptions = {
  intensity: 1,
  exponent: 1,
  distance: 10,
  fade: 0,
  roughnessFade: 1,
  thickness: 10,
  ior: 1.45,
  maxRoughness: 1,
  maxDepthDifference: 10,
  blend: 0.9,
  correction: 1,
  correctionRadius: 1,
  blur: 0.5,
  blurKernel: 1,
  blurSharpness: 10,
  jitter: 0,
  jitterRoughness: 0,
  steps: 20,
  refineSteps: 5,
  missedRays: true,
  useNormalMap: true,
  useRoughnessMap: true,
  resolutionScale: 1,
  velocityResolutionScale: 1
};
const temporalResolve = (
  /* glsl */
  `
  uniform sampler2D inputTexture;
  uniform sampler2D accumulatedTexture;
  uniform sampler2D velocityTexture;
  uniform sampler2D lastVelocityTexture;
  uniform float blend;
  uniform float correction;
  uniform float exponent;
  uniform float samples;
  uniform vec2 invTexSize;
  uniform mat4 curInverseProjectionMatrix;
  uniform mat4 curCameraMatrixWorld;
  uniform mat4 prevInverseProjectionMatrix;
  uniform mat4 prevCameraMatrixWorld;
  varying vec2 vUv;

  #define MAX_NEIGHBOR_DEPTH_DIFFERENCE 0.001
  #define FLOAT_EPSILON 0.00001
  #define FLOAT_ONE_MINUS_EPSILON 0.99999

  vec3 transformexponent;
  vec3 undoColorTransformExponent;

  vec3 transformColor(vec3 color) {
    if (exponent == 1.0) return color;
    return pow(abs(color), transformexponent);
  }

  vec3 undoColorTransform(vec3 color) {
    if (exponent == 1.0) return color;
    return max(pow(abs(color), undoColorTransformExponent), vec3(0.0));
  }

  void main() {
    if (exponent != 1.0){
      transformexponent = vec3(1.0 / exponent);
      undoColorTransformExponent = vec3(exponent);
    }

    vec4 inputTexel = textureLod(inputTexture, vUv, 0.0);
    vec4 accumulatedTexel;
    vec3 inputColor = transformColor(inputTexel.rgb);
    vec3 accumulatedColor;
    float alpha = inputTexel.a;
    float velocityDisocclusion;
    bool didReproject = false;

    #ifdef boxBlur
      vec3 boxBlurredColor = inputTexel.rgb;
    #endif

    vec4 velocity = textureLod(velocityTexture, vUv, 0.0);
    bool isMoving = alpha < 1.0 || dot(velocity.xy, velocity.xy) > 0.0;
    if (isMoving) {
      vec3 minNeighborColor = inputColor;
      vec3 maxNeighborColor = inputColor;
      vec3 col;
      vec2 neighborUv;
      vec2 reprojectedUv = vUv-velocity.xy;
      vec4 lastVelocity = textureLod(lastVelocityTexture, reprojectedUv, 0.0);
      float depth = velocity.b;
      float closestDepth = depth;
      float lastClosestDepth = lastVelocity.b;
      float neighborDepth;
      float lastNeighborDepth;

      for (int x = -correctionRadius; x <= correctionRadius; x++) {
        for (int y = -correctionRadius; y <= correctionRadius; y++) {
          if (x != 0 || y != 0) {
            neighborUv = vUv + vec2(x,y) * invTexSize;
            vec4 neigborVelocity = textureLod(velocityTexture, neighborUv, 0.0);
            neighborDepth = neigborVelocity.b;
            col = textureLod(inputTexture, neighborUv, 0.0).xyz;
            int absX = abs(x);
            int absY = abs(y);

            #ifdef dilation
              if (absX == 1 && absY == 1) {
                if (neighborDepth > closestDepth) {
                  velocity=neigborVelocity;
                  closestDepth=neighborDepth;
                }

                vec4 lastNeighborVelocity = textureLod(velocityTexture, vUv + vec2(x, y) * invTexSize, 0.0);
                lastNeighborDepth = lastNeighborVelocity.b;

                if (neighborDepth > closestDepth) {
                  lastVelocity = lastNeighborVelocity;
                  lastClosestDepth = lastNeighborDepth;
                }
              }
            #endif

            if (abs(depth-neighborDepth) < MAX_NEIGHBOR_DEPTH_DIFFERENCE) {
              #ifdef boxBlur
                if (absX <= 2 && absY <= 2) boxBlurredColor += col;
              #endif

              col = transformColor(col);
              minNeighborColor = min(col, minNeighborColor);
              maxNeighborColor = max(col, maxNeighborColor);
            }
          }
        }
      }

      float velocityLength = length(lastVelocity.xy - velocity.xy);
      velocityDisocclusion = (velocityLength - 0.000005) * 10.0;
      velocityDisocclusion *= velocityDisocclusion;
      reprojectedUv = vUv - velocity.xy;

      #ifdef boxBlur
        float pxRadius = correctionRadius > 5 ? 121.0 : pow(float(correctionRadius * 2 + 1), 2.0);
        boxBlurredColor /= pxRadius;
        boxBlurredColor = transformColor(boxBlurredColor);
      #endif

      if (
        reprojectedUv.x >=0.0 &&
        reprojectedUv.x <= 1.0 &&
        reprojectedUv.y >= 0.0 &&
        reprojectedUv.y <= 1.0
      ) {
        accumulatedTexel = textureLod(accumulatedTexture, reprojectedUv, 0.0);
        accumulatedColor = transformColor(accumulatedTexel.rgb);
        vec3 clampedColor = clamp(accumulatedColor, minNeighborColor, maxNeighborColor);
        accumulatedColor = mix(accumulatedColor, clampedColor, correction);
        didReproject = true;
      } else {
        #ifdef boxBlur
          accumulatedColor=boxBlurredColor;
        #else
          accumulatedColor=inputColor;
        #endif
      }

      if (velocity.r > FLOAT_ONE_MINUS_EPSILON && velocity.g > FLOAT_ONE_MINUS_EPSILON) {
        alpha = 0.0;
        velocityDisocclusion = 1.0;
      }
    } else {
      accumulatedColor = transformColor(textureLod(accumulatedTexture, vUv, 0.0).rgb);
    }

    vec3 outputColor = inputColor;

    #include <custom_compose_shader>

    gl_FragColor = vec4(undoColorTransform(outputColor), alpha);
  }
`
);
class TemporalResolveMaterial extends THREE.ShaderMaterial {
  constructor(customComposeShader) {
    const fragmentShader2 = temporalResolve.replace("#include <custom_compose_shader>", customComposeShader);
    super({
      type: "TemporalResolveMaterial",
      uniforms: {
        inputTexture: new THREE.Uniform(null),
        accumulatedTexture: new THREE.Uniform(null),
        velocityTexture: new THREE.Uniform(null),
        lastVelocityTexture: new THREE.Uniform(null),
        samples: new THREE.Uniform(1),
        blend: new THREE.Uniform(0.5),
        correction: new THREE.Uniform(1),
        exponent: new THREE.Uniform(1),
        invTexSize: new THREE.Uniform(new THREE.Vector2())
      },
      defines: {
        correctionRadius: 1
      },
      vertexShader,
      fragmentShader: fragmentShader2
    });
  }
}
const prev_skinning_pars_vertex = (
  /* glsl */
  `
    #ifdef USE_SKINNING
      #ifdef BONE_TEXTURE
        uniform sampler2D prevBoneTexture;
        mat4 getPrevBoneMatrix( const in float i ) {
          float j = i * 4.0;
          float x = mod( j, float( boneTextureSize ) );
          float y = floor( j / float( boneTextureSize ) );
          float dx = 1.0 / float( boneTextureSize );
          float dy = 1.0 / float( boneTextureSize );
          y = dy * ( y + 0.5 );
          vec4 v1 = texture2D( prevBoneTexture, vec2( dx * ( x + 0.5 ), y ) );
          vec4 v2 = texture2D( prevBoneTexture, vec2( dx * ( x + 1.5 ), y ) );
          vec4 v3 = texture2D( prevBoneTexture, vec2( dx * ( x + 2.5 ), y ) );
          vec4 v4 = texture2D( prevBoneTexture, vec2( dx * ( x + 3.5 ), y ) );
          mat4 bone = mat4( v1, v2, v3, v4 );
          return bone;
        }
      #else
        uniform mat4 prevBoneMatrices[ MAX_BONES ];
        mat4 getPrevBoneMatrix( const in float i ) {
          mat4 bone = prevBoneMatrices[ int(i) ];
          return bone;
        }
      #endif
    #endif
`
);
const velocity_vertex = (
  /* glsl */
  `
    vec3 transformed;

    // Get the normal
    ${THREE.ShaderChunk.skinbase_vertex}
    ${THREE.ShaderChunk.beginnormal_vertex}
    ${THREE.ShaderChunk.skinnormal_vertex}
    ${THREE.ShaderChunk.defaultnormal_vertex}

    // Get the current vertex position
    transformed = vec3( position );
    ${THREE.ShaderChunk.skinning_vertex}
    newPosition = velocityMatrix * vec4( transformed, 1.0 );

    // Get the previous vertex position
    transformed = vec3( position );
    ${THREE.ShaderChunk.skinbase_vertex.replace(/mat4 /g, "").replace(/getBoneMatrix/g, "getPrevBoneMatrix")}
    ${THREE.ShaderChunk.skinning_vertex.replace(/vec4 /g, "")}
    prevPosition = prevVelocityMatrix * vec4( transformed, 1.0 );

    gl_Position = newPosition;
`
);
class VelocityMaterial extends THREE.ShaderMaterial {
  constructor() {
    super({
      uniforms: {
        prevVelocityMatrix: {
          value: new THREE.Matrix4()
        },
        velocityMatrix: {
          value: new THREE.Matrix4()
        },
        prevBoneTexture: {
          value: null
        },
        interpolateGeometry: {
          value: 0
        },
        intensity: {
          value: 1
        },
        boneTexture: {
          value: null
        },
        alphaTest: {
          value: 0
        },
        map: {
          value: null
        },
        alphaMap: {
          value: null
        },
        opacity: {
          value: 1
        }
      },
      vertexShader: (
        /* glsl */
        `
                    #define MAX_BONES 1024

                    ${THREE.ShaderChunk.skinning_pars_vertex}
                    ${prev_skinning_pars_vertex}

                    uniform mat4 velocityMatrix;
                    uniform mat4 prevVelocityMatrix;
                    uniform float interpolateGeometry;
                    varying vec4 prevPosition;
                    varying vec4 newPosition;
          varying vec2 vHighPrecisionZW;

                    void main() {

                        ${velocity_vertex}

            vHighPrecisionZW = gl_Position.zw;

                    }`
      ),
      fragmentShader: (
        /* glsl */
        `
                    uniform float intensity;
                    varying vec4 prevPosition;
                    varying vec4 newPosition;
          varying vec2 vHighPrecisionZW;

                    void main() {
            #ifdef FULL_MOVEMENT
            gl_FragColor = vec4( 1., 1., 1. - gl_FragCoord.z, 0. );
            return;
            #endif

                        vec2 pos0 = (prevPosition.xy / prevPosition.w) * 0.5 + 0.5;
                        vec2 pos1 = (newPosition.xy / newPosition.w) * 0.5 + 0.5;

                        vec2 vel = pos1 - pos0;

            float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;

                        gl_FragColor = vec4( vel, 1. - fragCoordZ, 0. );

                    }`
      )
    });
    this.isVelocityMaterial = true;
  }
}
const backgroundColor = new THREE.Color(0);
const updateProperties = ["visible", "wireframe", "side"];
class VelocityPass extends postprocessing.Pass {
  constructor(scene, camera) {
    var _window, _window2;
    super("VelocityPass");
    this.cachedMaterials = /* @__PURE__ */ new WeakMap();
    this.lastCameraTransform = {
      position: new THREE.Vector3(),
      quaternion: new THREE.Quaternion()
    };
    this.visibleMeshes = [];
    this.renderedMeshesThisFrame = 0;
    this.renderedMeshesLastFrame = 0;
    this._scene = scene;
    this._camera = camera;
    this.renderTarget = new THREE.WebGLRenderTarget(
      ((_window = window) == null ? void 0 : _window.innerWidth) || 1e3,
      ((_window2 = window) == null ? void 0 : _window2.innerHeight) || 1e3,
      {
        type: THREE.HalfFloatType
      }
    );
  }
  setVelocityMaterialInScene() {
    this.renderedMeshesThisFrame = 0;
    this.visibleMeshes = getVisibleChildren(this._scene);
    for (const c of this.visibleMeshes) {
      var _c$skeleton2;
      const originalMaterial = c.material;
      let [cachedOriginalMaterial, velocityMaterial] = this.cachedMaterials.get(c) || [];
      if (originalMaterial !== cachedOriginalMaterial) {
        var _c$skeleton;
        velocityMaterial = new VelocityMaterial();
        velocityMaterial.lastMatrixWorld = new THREE.Matrix4();
        c.material = velocityMaterial;
        if ((_c$skeleton = c.skeleton) != null && _c$skeleton.boneTexture)
          this.saveBoneTexture(c);
        this.cachedMaterials.set(c, [originalMaterial, velocityMaterial]);
      }
      velocityMaterial.uniforms.velocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix);
      if (c.userData.needsUpdatedReflections || originalMaterial.map instanceof THREE.VideoTexture) {
        if (!("FULL_MOVEMENT" in velocityMaterial.defines))
          velocityMaterial.needsUpdate = true;
        velocityMaterial.defines.FULL_MOVEMENT = "";
      } else {
        if ("FULL_MOVEMENT" in velocityMaterial.defines) {
          delete velocityMaterial.defines.FULL_MOVEMENT;
          velocityMaterial.needsUpdate = true;
        }
      }
      c.visible = this.cameraMovedThisFrame || !c.matrixWorld.equals(velocityMaterial.lastMatrixWorld) || c.skeleton || "FULL_MOVEMENT" in velocityMaterial.defines;
      c.material = velocityMaterial;
      if (!c.visible)
        continue;
      this.renderedMeshesThisFrame++;
      for (const prop of updateProperties)
        velocityMaterial[prop] = originalMaterial[prop];
      if ((_c$skeleton2 = c.skeleton) != null && _c$skeleton2.boneTexture) {
        velocityMaterial.defines.USE_SKINNING = "";
        velocityMaterial.defines.BONE_TEXTURE = "";
        velocityMaterial.uniforms.boneTexture.value = c.skeleton.boneTexture;
      }
    }
  }
  saveBoneTexture(object) {
    let boneTexture = object.material.uniforms.prevBoneTexture.value;
    if (boneTexture && boneTexture.image.width === object.skeleton.boneTexture.width) {
      boneTexture = object.material.uniforms.prevBoneTexture.value;
      boneTexture.image.data.set(object.skeleton.boneTexture.image.data);
    } else {
      var _boneTexture;
      (_boneTexture = boneTexture) == null ? void 0 : _boneTexture.dispose();
      const boneMatrices = object.skeleton.boneTexture.image.data.slice();
      const size = object.skeleton.boneTexture.image.width;
      boneTexture = new THREE.DataTexture(boneMatrices, size, size, THREE.RGBAFormat, THREE.FloatType);
      object.material.uniforms.prevBoneTexture.value = boneTexture;
      boneTexture.needsUpdate = true;
    }
  }
  unsetVelocityMaterialInScene() {
    for (const c of this.visibleMeshes) {
      if (c.material.isVelocityMaterial) {
        var _c$skeleton3;
        c.visible = true;
        c.material.lastMatrixWorld.copy(c.matrixWorld);
        c.material.uniforms.prevVelocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix);
        if ((_c$skeleton3 = c.skeleton) != null && _c$skeleton3.boneTexture)
          this.saveBoneTexture(c);
        c.material = this.cachedMaterials.get(c)[0];
      }
    }
  }
  setSize(width, height) {
    this.renderTarget.setSize(width, height);
  }
  renderVelocity(renderer) {
    renderer.setRenderTarget(this.renderTarget);
    if (this.renderedMeshesThisFrame > 0) {
      const { background } = this._scene;
      this._scene.background = backgroundColor;
      renderer.render(this._scene, this._camera);
      this._scene.background = background;
    } else {
      renderer.clearColor();
    }
  }
  checkCameraMoved() {
    const moveDist = this.lastCameraTransform.position.distanceToSquared(this._camera.position);
    const rotateDist = 8 * (1 - this.lastCameraTransform.quaternion.dot(this._camera.quaternion));
    if (moveDist > 1e-6 || rotateDist > 1e-6) {
      this.lastCameraTransform.position.copy(this._camera.position);
      this.lastCameraTransform.quaternion.copy(this._camera.quaternion);
      return true;
    }
    return false;
  }
  render(renderer) {
    this.cameraMovedThisFrame = this.checkCameraMoved();
    this.setVelocityMaterialInScene();
    if (this.renderedMeshesThisFrame > 0 || this.renderedMeshesLastFrame > 0)
      this.renderVelocity(renderer);
    this.unsetVelocityMaterialInScene();
    this.renderedMeshesLastFrame = this.renderedMeshesThisFrame;
  }
}
const zeroVec2 = new THREE.Vector2();
class TemporalResolvePass extends postprocessing.Pass {
  constructor(scene, camera, customComposeShader, options = {}) {
    super("TemporalResolvePass");
    this.velocityPass = null;
    this.velocityResolutionScale = 1;
    this.samples = 1;
    this.lastCameraTransform = {
      position: new THREE.Vector3(),
      quaternion: new THREE.Quaternion()
    };
    this._scene = scene;
    this._camera = camera;
    this.renderTarget = new THREE.WebGLRenderTarget(1, 1, {
      minFilter: THREE.LinearFilter,
      magFilter: THREE.LinearFilter,
      type: THREE.HalfFloatType,
      depthBuffer: false
    });
    this.velocityPass = new VelocityPass(scene, camera);
    this.fullscreenMaterial = new TemporalResolveMaterial(customComposeShader);
    this.fullscreenMaterial.defines.correctionRadius = options.correctionRadius || 1;
    if (options.dilation)
      this.fullscreenMaterial.defines.dilation = "";
    if (options.boxBlur)
      this.fullscreenMaterial.defines.boxBlur = "";
    this.setupFramebuffers(1, 1);
    this.checkCanUseSharedVelocityTexture();
  }
  dispose() {
    if (this._scene.userData.velocityTexture === this.velocityPass.renderTarget.texture) {
      delete this._scene.userData.velocityTexture;
      delete this._scene.userData.lastVelocityTexture;
    }
    this.renderTarget.dispose();
    this.accumulatedTexture.dispose();
    this.fullscreenMaterial.dispose();
    this.velocityPass.dispose();
  }
  setSize(width, height) {
    this.renderTarget.setSize(width, height);
    this.velocityPass.setSize(width * this.velocityResolutionScale, height * this.velocityResolutionScale);
    this.velocityPass.renderTarget.texture.minFilter = this.velocityResolutionScale === 1 ? THREE.NearestFilter : THREE.LinearFilter;
    this.velocityPass.renderTarget.texture.magFilter = this.velocityResolutionScale === 1 ? THREE.NearestFilter : THREE.LinearFilter;
    this.velocityPass.renderTarget.texture.needsUpdate = true;
    this.fullscreenMaterial.uniforms.invTexSize.value.set(1 / width, 1 / height);
    this.setupFramebuffers(width, height);
  }
  setupFramebuffers(width, height) {
    if (this.accumulatedTexture)
      this.accumulatedTexture.dispose();
    if (this.lastVelocityTexture)
      this.lastVelocityTexture.dispose();
    this.accumulatedTexture = new THREE.FramebufferTexture(width, height, THREE.RGBAFormat);
    this.accumulatedTexture.minFilter = THREE.LinearFilter;
    this.accumulatedTexture.magFilter = THREE.LinearFilter;
    this.accumulatedTexture.type = THREE.HalfFloatType;
    this.lastVelocityTexture = new THREE.FramebufferTexture(
      width * this.velocityResolutionScale,
      height * this.velocityResolutionScale,
      THREE.RGBAFormat
    );
    this.lastVelocityTexture.minFilter = this.velocityResolutionScale === 1 ? THREE.NearestFilter : THREE.LinearFilter;
    this.lastVelocityTexture.magFilter = this.velocityResolutionScale === 1 ? THREE.NearestFilter : THREE.LinearFilter;
    this.lastVelocityTexture.type = THREE.HalfFloatType;
    this.fullscreenMaterial.uniforms.accumulatedTexture.value = this.accumulatedTexture;
    this.fullscreenMaterial.uniforms.lastVelocityTexture.value = this.lastVelocityTexture;
    this.fullscreenMaterial.needsUpdate = true;
  }
  checkCanUseSharedVelocityTexture() {
    const canUseSharedVelocityTexture = this._scene.userData.velocityTexture && this.velocityPass.renderTarget.texture !== this._scene.userData.velocityTexture;
    if (canUseSharedVelocityTexture) {
      if (this.velocityPass.renderTarget.texture === this.fullscreenMaterial.uniforms.velocityTexture.value) {
        this.fullscreenMaterial.uniforms.lastVelocityTexture.value = this._scene.userData.lastVelocityTexture;
        this.fullscreenMaterial.uniforms.velocityTexture.value = this._scene.userData.velocityTexture;
        this.fullscreenMaterial.needsUpdate = true;
      }
    } else {
      if (this.velocityPass.renderTarget.texture !== this.fullscreenMaterial.uniforms.velocityTexture.value) {
        this.fullscreenMaterial.uniforms.velocityTexture.value = this.velocityPass.renderTarget.texture;
        this.fullscreenMaterial.uniforms.lastVelocityTexture.value = this.lastVelocityTexture;
        this.fullscreenMaterial.needsUpdate = true;
        if (!this._scene.userData.velocityTexture) {
          this._scene.userData.velocityTexture = this.velocityPass.renderTarget.texture;
          this._scene.userData.lastVelocityTexture = this.lastVelocityTexture;
        }
      }
    }
    return this.velocityPass.renderTarget.texture !== this.fullscreenMaterial.uniforms.velocityTexture.value;
  }
  checkNeedsResample() {
    const moveDist = this.lastCameraTransform.position.distanceToSquared(this._camera.position);
    const rotateDist = 8 * (1 - this.lastCameraTransform.quaternion.dot(this._camera.quaternion));
    if (moveDist > 1e-6 || rotateDist > 1e-6) {
      this.samples = 1;
      this.lastCameraTransform.position.copy(this._camera.position);
      this.lastCameraTransform.quaternion.copy(this._camera.quaternion);
    }
  }
  render(renderer) {
    this.samples++;
    this.checkNeedsResample();
    this.fullscreenMaterial.uniforms.samples.value = this.samples;
    renderer.setRenderTarget(this.renderTarget);
    renderer.render(this.scene, this.camera);
    if (Number(THREE.REVISION) >= 165) {
      renderer.copyFramebufferToTexture(this.accumulatedTexture, zeroVec2);
      renderer.setRenderTarget(this.velocityPass.renderTarget);
      renderer.copyFramebufferToTexture(this.lastVelocityTexture, zeroVec2);
    } else {
      renderer.copyFramebufferToTexture(zeroVec2, this.accumulatedTexture);
      renderer.setRenderTarget(this.velocityPass.renderTarget);
      renderer.copyFramebufferToTexture(zeroVec2, this.accumulatedTexture);
    }
  }
}
const halton = function halton2(index, base) {
  let fraction = 1;
  let result = 0;
  while (index > 0) {
    fraction /= base;
    result += fraction * (index % base);
    index = ~~(index / base);
  }
  return result;
};
const generateHalton23Points = (count) => {
  const data = [];
  let i = 1;
  const end = i + count;
  for (; i < end; i++) {
    data.push([halton(i, 2) - 0.5, halton(i, 3) - 0.5]);
  }
  return data;
};
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
const worldposReplace = (
  /* glsl */
  `
#if defined( USE_ENVMAP ) || defined(  ) || defined ( USE_SHADOWMAP )
    vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );

    #ifdef BOX_PROJECTED_ENV_MAP
        vWorldPosition = worldPosition.xyz;
    #endif
#endif
`
);
const boxProjectDefinitions = (
  /* glsl */
  `
#ifdef BOX_PROJECTED_ENV_MAP
    uniform vec3 envMapSize;
    uniform vec3 envMapPosition;
    varying vec3 vWorldPosition;

    vec3 parallaxCorrectNormal( vec3 v, vec3 cubeSize, vec3 cubePos ) {
        vec3 nDir = normalize( v );

        vec3 rbmax = ( .5 * cubeSize + cubePos - vWorldPosition ) / nDir;
        vec3 rbmin = ( -.5 * cubeSize + cubePos - vWorldPosition ) / nDir;

        vec3 rbminmax;

        rbminmax.x = ( nDir.x > 0. ) ? rbmax.x : rbmin.x;
        rbminmax.y = ( nDir.y > 0. ) ? rbmax.y : rbmin.y;
        rbminmax.z = ( nDir.z > 0. ) ? rbmax.z : rbmin.z;

        float correction = min( min( rbminmax.x, rbminmax.y ), rbminmax.z );
        vec3 boxIntersection = vWorldPosition + nDir * correction;

        return boxIntersection - cubePos;
    }
#endif
`
);
const getIBLIrradiance_patch = (
  /* glsl */
  `
#ifdef BOX_PROJECTED_ENV_MAP
    worldNormal = parallaxCorrectNormal( worldNormal, envMapSize, envMapPosition );
#endif
`
);
const getIBLRadiance_patch = (
  /* glsl */
  `
#ifdef BOX_PROJECTED_ENV_MAP
    reflectVec = parallaxCorrectNormal( reflectVec, envMapSize, envMapPosition );
#endif
`
);
function useBoxProjectedEnvMap(shader, envMapPosition, envMapSize) {
  shader.defines.BOX_PROJECTED_ENV_MAP = "";
  shader.uniforms.envMapPosition = {
    value: envMapPosition
  };
  shader.uniforms.envMapSize = {
    value: envMapSize
  };
  const line1 = new RegExp(
    escapeRegExp("vec3 worldNormal = inverseTransformDirection ( normal , viewMatrix ) ;").replaceAll(" ", "\\s*"),
    "g"
  );
  const line2 = new RegExp(
    escapeRegExp("reflectVec = inverseTransformDirection ( reflectVec , viewMatrix ) ;").replaceAll(" ", "\\s*"),
    "g"
  );
  shader.vertexShader = "varying vec3 vWorldPosition;\n" + shader.vertexShader.replace("#include <worldpos_vertex>", worldposReplace);
  shader.fragmentShader = boxProjectDefinitions + "\n" + shader.fragmentShader.replace("#include <envmap_physical_pars_fragment>", THREE.ShaderChunk.envmap_physical_pars_fragment).replace(
    line1,
    `vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );
                ${getIBLIrradiance_patch}`
  ).replace(
    line2,
    `reflectVec = inverseTransformDirection( reflectVec, viewMatrix );
                ${getIBLRadiance_patch}`
  );
}
const noResetSamplesProperties = ["blur", "blurSharpness", "blurKernel"];
const defaultCubeRenderTarget = new THREE.WebGLCubeRenderTarget(1);
let pmremGenerator;
class SSREffect extends postprocessing.Effect {
  /**
   * @param {THREE.Scene} scene The scene of the SSR effect
   * @param {THREE.Camera} camera The camera with which SSR is being rendered
   * @param {SSROptions} [options] The optional options for the SSR effect
   */
  constructor(scene, camera, options = defaultSSROptions) {
    super("SSREffect", finalSSRShader, {
      type: "FinalSSRMaterial",
      uniforms: /* @__PURE__ */ new Map([
        ["reflectionsTexture", new THREE.Uniform(null)],
        ["blur", new THREE.Uniform(0)],
        ["blurSharpness", new THREE.Uniform(0)],
        ["blurKernel", new THREE.Uniform(0)]
      ]),
      defines: /* @__PURE__ */ new Map([["RENDER_MODE", "0"]])
    });
    this.haltonSequence = generateHalton23Points(1024);
    this.haltonIndex = 0;
    this.selection = new postprocessing.Selection();
    this.lastSize = void 0;
    this.cubeCamera = new THREE.CubeCamera(1e-3, 1e3, defaultCubeRenderTarget);
    this.usingBoxProjectedEnvMap = false;
    this._scene = scene;
    this._camera = camera;
    const trOptions = {
      boxBlur: true,
      dilation: true
    };
    options = { ...defaultSSROptions, ...options, ...trOptions };
    this.temporalResolvePass = new TemporalResolvePass(scene, camera, trCompose, options);
    this.uniforms.get("reflectionsTexture").value = this.temporalResolvePass.renderTarget.texture;
    this.reflectionsPass = new ReflectionsPass(this, options);
    this.temporalResolvePass.fullscreenMaterial.uniforms.inputTexture.value = this.reflectionsPass.renderTarget.texture;
    this.lastSize = {
      width: options.width,
      height: options.height,
      resolutionScale: options.resolutionScale,
      velocityResolutionScale: options.velocityResolutionScale
    };
    this.setSize(options.width, options.height);
    this.makeOptionsReactive(options);
  }
  makeOptionsReactive(options) {
    let needsUpdate = false;
    const reflectionPassFullscreenMaterialUniforms = this.reflectionsPass.fullscreenMaterial.uniforms;
    const reflectionPassFullscreenMaterialUniformsKeys = Object.keys(reflectionPassFullscreenMaterialUniforms);
    for (const key of Object.keys(options)) {
      Object.defineProperty(this, key, {
        get() {
          return options[key];
        },
        set(value) {
          if (options[key] === value && needsUpdate)
            return;
          options[key] = value;
          if (!noResetSamplesProperties.includes(key)) {
            this.setSize(this.lastSize.width, this.lastSize.height, true);
          }
          switch (key) {
            case "resolutionScale":
              this.setSize(this.lastSize.width, this.lastSize.height);
              break;
            case "velocityResolutionScale":
              this.temporalResolvePass.velocityResolutionScale = value;
              this.setSize(this.lastSize.width, this.lastSize.height, true);
              break;
            case "blur":
              this.uniforms.get("blur").value = value;
              break;
            case "blurSharpness":
              this.uniforms.get("blurSharpness").value = value;
              break;
            case "blurKernel":
              this.uniforms.get("blurKernel").value = value;
              break;
            case "steps":
              this.reflectionsPass.fullscreenMaterial.defines.steps = parseInt(value);
              this.reflectionsPass.fullscreenMaterial.needsUpdate = needsUpdate;
              break;
            case "refineSteps":
              this.reflectionsPass.fullscreenMaterial.defines.refineSteps = parseInt(value);
              this.reflectionsPass.fullscreenMaterial.needsUpdate = needsUpdate;
              break;
            case "missedRays":
              if (value) {
                this.reflectionsPass.fullscreenMaterial.defines.missedRays = "";
              } else {
                delete this.reflectionsPass.fullscreenMaterial.defines.missedRays;
              }
              this.reflectionsPass.fullscreenMaterial.needsUpdate = needsUpdate;
              break;
            case "correctionRadius":
              this.temporalResolvePass.fullscreenMaterial.defines.correctionRadius = Math.round(value);
              this.temporalResolvePass.fullscreenMaterial.needsUpdate = needsUpdate;
              break;
            case "blend":
              this.temporalResolvePass.fullscreenMaterial.uniforms.blend.value = value;
              break;
            case "correction":
              this.temporalResolvePass.fullscreenMaterial.uniforms.correction.value = value;
              break;
            case "exponent":
              this.temporalResolvePass.fullscreenMaterial.uniforms.exponent.value = value;
              break;
            case "distance":
              reflectionPassFullscreenMaterialUniforms.rayDistance.value = value;
            default:
              if (reflectionPassFullscreenMaterialUniformsKeys.includes(key)) {
                reflectionPassFullscreenMaterialUniforms[key].value = value;
              }
          }
        }
      });
      this[key] = options[key];
    }
    needsUpdate = true;
  }
  setSize(width, height, force = false) {
    if (!force && width === this.lastSize.width && height === this.lastSize.height && this.resolutionScale === this.lastSize.resolutionScale && this.velocityResolutionScale === this.lastSize.velocityResolutionScale)
      return;
    this.temporalResolvePass.setSize(width, height);
    this.reflectionsPass.setSize(width, height);
    this.lastSize = {
      width,
      height,
      resolutionScale: this.resolutionScale,
      velocityResolutionScale: this.velocityResolutionScale
    };
  }
  generateBoxProjectedEnvMapFallback(renderer, position = new THREE.Vector3(), size = new THREE.Vector3(), envMapSize = 512) {
    this.cubeCamera.renderTarget.dispose();
    this.cubeCamera.renderTarget = new THREE.WebGLCubeRenderTarget(envMapSize);
    this.cubeCamera.position.copy(position);
    this.cubeCamera.updateMatrixWorld();
    this.cubeCamera.update(renderer, this._scene);
    if (!pmremGenerator) {
      pmremGenerator = new THREE.PMREMGenerator(renderer);
      pmremGenerator.compileCubemapShader();
    }
    const envMap = pmremGenerator.fromCubemap(this.cubeCamera.renderTarget.texture).texture;
    envMap.minFilter = THREE.LinearFilter;
    envMap.magFilter = THREE.LinearFilter;
    const reflectionsMaterial = this.reflectionsPass.fullscreenMaterial;
    useBoxProjectedEnvMap(reflectionsMaterial, position, size);
    reflectionsMaterial.fragmentShader = reflectionsMaterial.fragmentShader.replace("vec3 worldPos", "worldPos").replace("varying vec3 vWorldPosition;", "vec3 worldPos;");
    reflectionsMaterial.uniforms.envMapPosition.value.copy(position);
    reflectionsMaterial.uniforms.envMapSize.value.copy(size);
    setupEnvMap(reflectionsMaterial, envMap, envMapSize);
    this.usingBoxProjectedEnvMap = true;
    return envMap;
  }
  setIBLRadiance(iblRadiance, renderer) {
    this._scene.traverse((c) => {
      if (c.material) {
        var _renderer$properties$;
        const uniforms = (_renderer$properties$ = renderer.properties.get(c.material)) == null ? void 0 : _renderer$properties$.uniforms;
        if (uniforms && "disableIBLRadiance" in uniforms) {
          uniforms.disableIBLRadiance.value = iblRadiance;
        }
      }
    });
  }
  deleteBoxProjectedEnvMapFallback() {
    const reflectionsMaterial = this.reflectionsPass.fullscreenMaterial;
    reflectionsMaterial.uniforms.envMap.value = null;
    reflectionsMaterial.fragmentShader = reflectionsMaterial.fragmentShader.replace("worldPos = ", "vec3 worldPos = ");
    delete reflectionsMaterial.defines.BOX_PROJECTED_ENV_MAP;
    reflectionsMaterial.needsUpdate = true;
    this.usingBoxProjectedEnvMap = false;
  }
  dispose() {
    super.dispose();
    this.reflectionsPass.dispose();
    this.temporalResolvePass.dispose();
  }
  update(renderer, inputBuffer) {
    if (!this.usingBoxProjectedEnvMap && this._scene.environment) {
      const reflectionsMaterial = this.reflectionsPass.fullscreenMaterial;
      let envMap = null;
      this._scene.traverse((c) => {
        if (!envMap && c.material && !c.material.envMap) {
          const properties = renderer.properties.get(c.material);
          if ("envMap" in properties && properties.envMap instanceof THREE.Texture)
            envMap = properties.envMap;
        }
      });
      if (envMap) {
        const envMapCubeUVHeight = this._scene.environment.image.height;
        setupEnvMap(reflectionsMaterial, envMap, envMapCubeUVHeight);
      }
    }
    this.haltonIndex = (this.haltonIndex + 1) % this.haltonSequence.length;
    const [x, y] = this.haltonSequence[this.haltonIndex];
    const { width, height } = this.lastSize;
    this.temporalResolvePass.velocityPass.render(renderer);
    if (this._camera.setViewOffset)
      this._camera.setViewOffset(width, height, x, y, width, height);
    this.reflectionsPass.render(renderer, inputBuffer);
    this.temporalResolvePass.render(renderer);
    this._camera.clearViewOffset();
  }
  static patchDirectEnvIntensity(envMapIntensity = 0) {
    if (envMapIntensity === 0) {
      THREE.ShaderChunk.envmap_physical_pars_fragment = THREE.ShaderChunk.envmap_physical_pars_fragment.replace(
        "vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {",
        "vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { return vec3(0.0);"
      );
    } else {
      THREE.ShaderChunk.envmap_physical_pars_fragment = THREE.ShaderChunk.envmap_physical_pars_fragment.replace(
        "vec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );",
        "vec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness ) * " + envMapIntensity.toFixed(5) + ";"
      );
    }
  }
}
exports.SSREffect = SSREffect;
exports.defaultSSROptions = defaultSSROptions;
//# sourceMappingURL=screen-space-reflections.cjs.map
