"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const ReflectorForSSRPass = /* @__PURE__ */ (() => {
  const _ReflectorForSSRPass = class extends THREE.Mesh {
    constructor(geometry, options = {}) {
      super(geometry);
      this.isReflectorForSSRPass = true;
      this.type = "ReflectorForSSRPass";
      const scope = this;
      const color = options.color !== void 0 ? new THREE.Color(options.color) : new THREE.Color(8355711);
      const textureWidth = options.textureWidth || 512;
      const textureHeight = options.textureHeight || 512;
      const clipBias = options.clipBias || 0;
      const shader = options.shader || _ReflectorForSSRPass.ReflectorShader;
      const useDepthTexture = options.useDepthTexture === true;
      const yAxis = new THREE.Vector3(0, 1, 0);
      const vecTemp0 = new THREE.Vector3();
      const vecTemp1 = new THREE.Vector3();
      scope.needsUpdate = false;
      scope.maxDistance = _ReflectorForSSRPass.ReflectorShader.uniforms.maxDistance.value;
      scope.opacity = _ReflectorForSSRPass.ReflectorShader.uniforms.opacity.value;
      scope.color = color;
      scope.resolution = options.resolution || new THREE.Vector2(window.innerWidth, window.innerHeight);
      scope._distanceAttenuation = _ReflectorForSSRPass.ReflectorShader.defines.DISTANCE_ATTENUATION;
      Object.defineProperty(scope, "distanceAttenuation", {
        get() {
          return scope._distanceAttenuation;
        },
        set(val) {
          if (scope._distanceAttenuation === val)
            return;
          scope._distanceAttenuation = val;
          scope.material.defines.DISTANCE_ATTENUATION = val;
          scope.material.needsUpdate = true;
        }
      });
      scope._fresnel = _ReflectorForSSRPass.ReflectorShader.defines.FRESNEL;
      Object.defineProperty(scope, "fresnel", {
        get() {
          return scope._fresnel;
        },
        set(val) {
          if (scope._fresnel === val)
            return;
          scope._fresnel = val;
          scope.material.defines.FRESNEL = val;
          scope.material.needsUpdate = true;
        }
      });
      const normal = new THREE.Vector3();
      const reflectorWorldPosition = new THREE.Vector3();
      const cameraWorldPosition = new THREE.Vector3();
      const rotationMatrix = new THREE.Matrix4();
      const lookAtPosition = new THREE.Vector3(0, 0, -1);
      const view = new THREE.Vector3();
      const target = new THREE.Vector3();
      const textureMatrix = new THREE.Matrix4();
      const virtualCamera = new THREE.PerspectiveCamera();
      let depthTexture;
      if (useDepthTexture) {
        depthTexture = new THREE.DepthTexture();
        depthTexture.type = THREE.UnsignedShortType;
        depthTexture.minFilter = THREE.NearestFilter;
        depthTexture.magFilter = THREE.NearestFilter;
      }
      const parameters = {
        depthTexture: useDepthTexture ? depthTexture : null,
        type: THREE.HalfFloatType
      };
      const renderTarget = new THREE.WebGLRenderTarget(textureWidth, textureHeight, parameters);
      const material = new THREE.ShaderMaterial({
        transparent: useDepthTexture,
        defines: Object.assign({}, _ReflectorForSSRPass.ReflectorShader.defines, {
          useDepthTexture
        }),
        uniforms: THREE.UniformsUtils.clone(shader.uniforms),
        fragmentShader: shader.fragmentShader,
        vertexShader: shader.vertexShader
      });
      material.uniforms["tDiffuse"].value = renderTarget.texture;
      material.uniforms["color"].value = scope.color;
      material.uniforms["textureMatrix"].value = textureMatrix;
      if (useDepthTexture) {
        material.uniforms["tDepth"].value = renderTarget.depthTexture;
      }
      this.material = material;
      const globalPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), clipBias);
      const globalPlanes = [globalPlane];
      this.doRender = function(renderer, scene, camera) {
        material.uniforms["maxDistance"].value = scope.maxDistance;
        material.uniforms["color"].value = scope.color;
        material.uniforms["opacity"].value = scope.opacity;
        vecTemp0.copy(camera.position).normalize();
        vecTemp1.copy(vecTemp0).reflect(yAxis);
        material.uniforms["fresnelCoe"].value = (vecTemp0.dot(vecTemp1) + 1) / 2;
        reflectorWorldPosition.setFromMatrixPosition(scope.matrixWorld);
        cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
        rotationMatrix.extractRotation(scope.matrixWorld);
        normal.set(0, 0, 1);
        normal.applyMatrix4(rotationMatrix);
        view.subVectors(reflectorWorldPosition, cameraWorldPosition);
        if (view.dot(normal) > 0)
          return;
        view.reflect(normal).negate();
        view.add(reflectorWorldPosition);
        rotationMatrix.extractRotation(camera.matrixWorld);
        lookAtPosition.set(0, 0, -1);
        lookAtPosition.applyMatrix4(rotationMatrix);
        lookAtPosition.add(cameraWorldPosition);
        target.subVectors(reflectorWorldPosition, lookAtPosition);
        target.reflect(normal).negate();
        target.add(reflectorWorldPosition);
        virtualCamera.position.copy(view);
        virtualCamera.up.set(0, 1, 0);
        virtualCamera.up.applyMatrix4(rotationMatrix);
        virtualCamera.up.reflect(normal);
        virtualCamera.lookAt(target);
        virtualCamera.far = camera.far;
        virtualCamera.updateMatrixWorld();
        virtualCamera.projectionMatrix.copy(camera.projectionMatrix);
        material.uniforms["virtualCameraNear"].value = camera.near;
        material.uniforms["virtualCameraFar"].value = camera.far;
        material.uniforms["virtualCameraMatrixWorld"].value = virtualCamera.matrixWorld;
        material.uniforms["virtualCameraProjectionMatrix"].value = camera.projectionMatrix;
        material.uniforms["virtualCameraProjectionMatrixInverse"].value = camera.projectionMatrixInverse;
        material.uniforms["resolution"].value = scope.resolution;
        textureMatrix.set(0.5, 0, 0, 0.5, 0, 0.5, 0, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 1);
        textureMatrix.multiply(virtualCamera.projectionMatrix);
        textureMatrix.multiply(virtualCamera.matrixWorldInverse);
        textureMatrix.multiply(scope.matrixWorld);
        const currentRenderTarget = renderer.getRenderTarget();
        const currentXrEnabled = renderer.xr.enabled;
        const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
        const currentClippingPlanes = renderer.clippingPlanes;
        renderer.xr.enabled = false;
        renderer.shadowMap.autoUpdate = false;
        renderer.clippingPlanes = globalPlanes;
        renderer.setRenderTarget(renderTarget);
        renderer.state.buffers.depth.setMask(true);
        if (renderer.autoClear === false)
          renderer.clear();
        renderer.render(scene, virtualCamera);
        renderer.xr.enabled = currentXrEnabled;
        renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
        renderer.clippingPlanes = currentClippingPlanes;
        renderer.setRenderTarget(currentRenderTarget);
        const viewport = camera.viewport;
        if (viewport !== void 0) {
          renderer.state.viewport(viewport);
        }
      };
      this.getRenderTarget = function() {
        return renderTarget;
      };
    }
  };
  let ReflectorForSSRPass2 = _ReflectorForSSRPass;
  __publicField(ReflectorForSSRPass2, "ReflectorShader", {
    defines: {
      DISTANCE_ATTENUATION: true,
      FRESNEL: true
    },
    uniforms: {
      color: { value: null },
      tDiffuse: { value: null },
      tDepth: { value: null },
      textureMatrix: { value: new THREE.Matrix4() },
      maxDistance: { value: 180 },
      opacity: { value: 0.5 },
      fresnelCoe: { value: null },
      virtualCameraNear: { value: null },
      virtualCameraFar: { value: null },
      virtualCameraProjectionMatrix: { value: new THREE.Matrix4() },
      virtualCameraMatrixWorld: { value: new THREE.Matrix4() },
      virtualCameraProjectionMatrixInverse: { value: new THREE.Matrix4() },
      resolution: { value: new THREE.Vector2() }
    },
    vertexShader: (
      /* glsl */
      `
		uniform mat4 textureMatrix;
		varying vec4 vUv;

		void main() {

			vUv = textureMatrix * vec4( position, 1.0 );

			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

		}`
    ),
    fragmentShader: (
      /* glsl */
      `
		uniform vec3 color;
		uniform sampler2D tDiffuse;
		uniform sampler2D tDepth;
		uniform float maxDistance;
		uniform float opacity;
		uniform float fresnelCoe;
		uniform float virtualCameraNear;
		uniform float virtualCameraFar;
		uniform mat4 virtualCameraProjectionMatrix;
		uniform mat4 virtualCameraProjectionMatrixInverse;
		uniform mat4 virtualCameraMatrixWorld;
		uniform vec2 resolution;
		varying vec4 vUv;
		#include <packing>
		float blendOverlay( float base, float blend ) {
			return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );
		}
		vec3 blendOverlay( vec3 base, vec3 blend ) {
			return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );
		}
		float getDepth( const in vec2 uv ) {
			return texture2D( tDepth, uv ).x;
		}
		float getViewZ( const in float depth ) {
			return perspectiveDepthToViewZ( depth, virtualCameraNear, virtualCameraFar );
		}
		vec3 getViewPosition( const in vec2 uv, const in float depth/*clip space*/, const in float clipW ) {
			vec4 clipPosition = vec4( ( vec3( uv, depth ) - 0.5 ) * 2.0, 1.0 );//ndc
			clipPosition *= clipW; //clip
			return ( virtualCameraProjectionMatrixInverse * clipPosition ).xyz;//view
		}
		void main() {
			vec4 base = texture2DProj( tDiffuse, vUv );
			#ifdef useDepthTexture
				vec2 uv=(gl_FragCoord.xy-.5)/resolution.xy;
				uv.x=1.-uv.x;
				float depth = texture2DProj( tDepth, vUv ).r;
				float viewZ = getViewZ( depth );
				float clipW = virtualCameraProjectionMatrix[2][3] * viewZ+virtualCameraProjectionMatrix[3][3];
				vec3 viewPosition=getViewPosition( uv, depth, clipW );
				vec3 worldPosition=(virtualCameraMatrixWorld*vec4(viewPosition,1)).xyz;
				if(worldPosition.y>maxDistance) discard;
				float op=opacity;
				#ifdef DISTANCE_ATTENUATION
					float ratio=1.-(worldPosition.y/maxDistance);
					float attenuation=ratio*ratio;
					op=opacity*attenuation;
				#endif
				#ifdef FRESNEL
					op*=fresnelCoe;
				#endif
				gl_FragColor = vec4( blendOverlay( base.rgb, color ), op );
			#else
				gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );
			#endif
		}
	`
    )
  });
  return ReflectorForSSRPass2;
})();
exports.ReflectorForSSRPass = ReflectorForSSRPass;
//# sourceMappingURL=ReflectorForSSRPass.cjs.map
