(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "three"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("three")); } else { var mod = { exports: {} }; factory(mod.exports, global.three); global.ReflectorForSSRPass = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.ReflectorForSSRPass = void 0; function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } Object.defineProperty(subClass, "prototype", { value: Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }), writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } var ReflectorForSSRPass = /*#__PURE__*/function (_Mesh) { _inherits(ReflectorForSSRPass, _Mesh); var _super = _createSuper(ReflectorForSSRPass); function ReflectorForSSRPass(geometry) { var _this; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, ReflectorForSSRPass); _this = _super.call(this, geometry); _this.type = 'ReflectorForSSRPass'; var scope = _assertThisInitialized(_this); var color = options.color !== undefined ? new _three.Color(options.color) : new _three.Color(0x7F7F7F); var textureWidth = options.textureWidth || 512; var textureHeight = options.textureHeight || 512; var clipBias = options.clipBias || 0; var shader = options.shader || ReflectorForSSRPass.ReflectorShader; var useDepthTexture = options.useDepthTexture === true; var yAxis = new _three.Vector3(0, 1, 0); var vecTemp0 = new _three.Vector3(); var 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: function get() { return scope._distanceAttenuation; }, set: function 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: function get() { return scope._fresnel; }, set: function set(val) { if (scope._fresnel === val) return; scope._fresnel = val; scope.material.defines.FRESNEL = val; scope.material.needsUpdate = true; } }); var normal = new _three.Vector3(); var reflectorWorldPosition = new _three.Vector3(); var cameraWorldPosition = new _three.Vector3(); var rotationMatrix = new _three.Matrix4(); var lookAtPosition = new _three.Vector3(0, 0, -1); var view = new _three.Vector3(); var target = new _three.Vector3(); var textureMatrix = new _three.Matrix4(); var virtualCamera = new _three.PerspectiveCamera(); var depthTexture; if (useDepthTexture) { depthTexture = new _three.DepthTexture(); depthTexture.type = _three.UnsignedShortType; depthTexture.minFilter = _three.NearestFilter; depthTexture.magFilter = _three.NearestFilter; } var parameters = { minFilter: _three.LinearFilter, magFilter: _three.LinearFilter, format: _three.RGBFormat, depthTexture: useDepthTexture ? depthTexture : null }; var renderTarget = new _three.WebGLRenderTarget(textureWidth, textureHeight, parameters); if (!_three.MathUtils.isPowerOfTwo(textureWidth) || !_three.MathUtils.isPowerOfTwo(textureHeight)) { renderTarget.texture.generateMipmaps = false; } var material = new _three.ShaderMaterial({ transparent: useDepthTexture, defines: Object.assign({}, ReflectorForSSRPass.ReflectorShader.defines, { useDepthTexture: 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; var globalPlane = new _three.Plane(new _three.Vector3(0, 1, 0), clipBias); var 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.; // TODO: Also need to use glsl viewPosition and viewNormal per pixel. reflectorWorldPosition.setFromMatrixPosition(scope.matrixWorld); cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld); rotationMatrix.extractRotation(scope.matrixWorld); normal.set(0, 0, 1); normal.applyMatrix4(rotationMatrix); view.subVectors(reflectorWorldPosition, cameraWorldPosition); // Avoid rendering when reflector is facing away 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; // Used in WebGLBackground 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; // Update the texture matrix textureMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0); textureMatrix.multiply(virtualCamera.projectionMatrix); textureMatrix.multiply(virtualCamera.matrixWorldInverse); textureMatrix.multiply(scope.matrixWorld); // Render renderTarget.texture.encoding = renderer.outputEncoding; // scope.visible = false; var currentRenderTarget = renderer.getRenderTarget(); var currentXrEnabled = renderer.xr.enabled; var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate; var currentClippingPlanes = renderer.clippingPlanes; renderer.xr.enabled = false; // Avoid camera modification renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows renderer.clippingPlanes = globalPlanes; renderer.setRenderTarget(renderTarget); renderer.state.buffers.depth.setMask(true); // make sure the depth buffer is writable so it can be properly cleared, see #18897 if (renderer.autoClear === false) renderer.clear(); renderer.render(scene, virtualCamera); renderer.xr.enabled = currentXrEnabled; renderer.shadowMap.autoUpdate = currentShadowAutoUpdate; renderer.clippingPlanes = currentClippingPlanes; renderer.setRenderTarget(currentRenderTarget); // Restore viewport var viewport = camera.viewport; if (viewport !== undefined) { renderer.state.viewport(viewport); } // scope.visible = true; }; _this.getRenderTarget = function () { return renderTarget; }; return _this; } return _createClass(ReflectorForSSRPass); }(_three.Mesh); _exports.ReflectorForSSRPass = ReflectorForSSRPass; ReflectorForSSRPass.prototype.isReflectorForSSRPass = true; ReflectorForSSRPass.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 */ "\n\t\tuniform mat4 textureMatrix;\n\t\tvarying vec4 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = textureMatrix * vec4( position, 1.0 );\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}", fragmentShader: /* glsl */ "\n\t\tuniform vec3 color;\n\t\tuniform sampler2D tDiffuse;\n\t\tuniform sampler2D tDepth;\n\t\tuniform float maxDistance;\n\t\tuniform float opacity;\n\t\tuniform float fresnelCoe;\n\t\tuniform float virtualCameraNear;\n\t\tuniform float virtualCameraFar;\n\t\tuniform mat4 virtualCameraProjectionMatrix;\n\t\tuniform mat4 virtualCameraProjectionMatrixInverse;\n\t\tuniform mat4 virtualCameraMatrixWorld;\n\t\tuniform vec2 resolution;\n\t\tvarying vec4 vUv;\n\t\t#include \n\t\tfloat blendOverlay( float base, float blend ) {\n\t\t\treturn( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );\n\t\t}\n\t\tvec3 blendOverlay( vec3 base, vec3 blend ) {\n\t\t\treturn vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );\n\t\t}\n\t\tfloat getDepth( const in vec2 uv ) {\n\t\t\treturn texture2D( tDepth, uv ).x;\n\t\t}\n\t\tfloat getViewZ( const in float depth ) {\n\t\t\treturn perspectiveDepthToViewZ( depth, virtualCameraNear, virtualCameraFar );\n\t\t}\n\t\tvec3 getViewPosition( const in vec2 uv, const in float depth/*clip space*/, const in float clipW ) {\n\t\t\tvec4 clipPosition = vec4( ( vec3( uv, depth ) - 0.5 ) * 2.0, 1.0 );//ndc\n\t\t\tclipPosition *= clipW; //clip\n\t\t\treturn ( virtualCameraProjectionMatrixInverse * clipPosition ).xyz;//view\n\t\t}\n\t\tvoid main() {\n\t\t\tvec4 base = texture2DProj( tDiffuse, vUv );\n\t\t\t#ifdef useDepthTexture\n\t\t\t\tvec2 uv=(gl_FragCoord.xy-.5)/resolution.xy;\n\t\t\t\tuv.x=1.-uv.x;\n\t\t\t\tfloat depth = texture2DProj( tDepth, vUv ).r;\n\t\t\t\tfloat viewZ = getViewZ( depth );\n\t\t\t\tfloat clipW = virtualCameraProjectionMatrix[2][3] * viewZ+virtualCameraProjectionMatrix[3][3];\n\t\t\t\tvec3 viewPosition=getViewPosition( uv, depth, clipW );\n\t\t\t\tvec3 worldPosition=(virtualCameraMatrixWorld*vec4(viewPosition,1)).xyz;\n\t\t\t\tif(worldPosition.y>maxDistance) discard;\n\t\t\t\tfloat op=opacity;\n\t\t\t\t#ifdef DISTANCE_ATTENUATION\n\t\t\t\t\tfloat ratio=1.-(worldPosition.y/maxDistance);\n\t\t\t\t\tfloat attenuation=ratio*ratio;\n\t\t\t\t\top=opacity*attenuation;\n\t\t\t\t#endif\n\t\t\t\t#ifdef FRESNEL\n\t\t\t\t\top*=fresnelCoe;\n\t\t\t\t#endif\n\t\t\t\tgl_FragColor = vec4( blendOverlay( base.rgb, color ), op );\n\t\t\t#else\n\t\t\t\tgl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );\n\t\t\t#endif\n\t\t}\n\t" }; });