UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

194 lines (193 loc) 7.98 kB
"use strict"; import { Mesh, Vector2, Vector3, Vector4, LinearFilter, Plane, Matrix4, PerspectiveCamera } from "three"; import { CoreRenderBlur } from "../../../core/render/Blur"; import { isBooleanTrue } from "../../../core/Type"; import { CoreTransform, rotateGeometry } from "../../../core/Transform"; import { Poly } from "../../../engine/Poly"; export const renderTargetParams = { minFilter: LinearFilter, magFilter: LinearFilter // format: RGBAFormat, // encoding: LinearEncoding, }; export class BaseReflector extends Mesh { constructor(geometry, _options) { super(geometry); this.geometry = geometry; this._options = _options; this.type = "BaseReflector"; this.reflectorPlane = new Plane(); this.normal = new Vector3(); this.reflectorWorldPosition = new Vector3(); this.cameraWorldPosition = new Vector3(); this.rotationMatrix = new Matrix4(); this.lookAtPosition = new Vector3(0, 0, -1); this.clipPlane = new Vector4(); this.view = new Vector3(); this.target = new Vector3(); this.q = new Vector4(); this.textureMatrix = new Matrix4(); this.virtualCamera = new PerspectiveCamera(); this.material = this._createMaterial(); this.onBeforeRender = this._onBeforeRender.bind(this); this._mirrorCameraMultipliedByMatrixWorld = true; this._onWindowResizeBound = this._onWindowResize.bind(this); if (this._options.renderer) { this._createRenderTarget(this._options.renderer); } this._addWindowResizeEvent(); } _createRenderTarget(renderer) { const { width, height } = this._getRendererSize(renderer); this.renderTarget = Poly.renderersController.createRenderTarget(width, height, renderTargetParams); if (this._options.multisamples > 0) { this.renderTarget.samples = this._options.multisamples; } this._assignMaterialRenderTarget(); this._coreRenderBlur = new CoreRenderBlur(new Vector2(width, height)); } dispose() { var _a, _b; this.geometry.dispose(); (_a = this.renderTarget) == null ? void 0 : _a.dispose(); (_b = this.material) == null ? void 0 : _b.dispose(); this.onBeforeRender = () => { }; this._removeWindowResizeEvent(); } _addWindowResizeEvent() { globalThis.addEventListener("resize", this._onWindowResizeBound.bind(this), false); } _removeWindowResizeEvent() { globalThis.removeEventListener("resize", this._onWindowResizeBound.bind(this), false); } _onWindowResize() { var _a, _b; this.traverseAncestors((object) => { if (!object.parent) { if (object.uuid != this._options.scene.uuid) { this._removeWindowResizeEvent(); } } }); const renderer = this._options.renderer; if (renderer) { const { width, height } = this._getRendererSize(renderer); (_a = this.renderTarget) == null ? void 0 : _a.setSize(width, height); (_b = this._coreRenderBlur) == null ? void 0 : _b.setSize(width, height); } } _getRendererSize(renderer) { const canvas = renderer.domElement; const width = canvas.width * this._options.pixelRatio; const height = canvas.height * this._options.pixelRatio; return { width, height }; } static rotateGeometry(geometry, direction) { rotateGeometry(geometry, direction, this.REFLECTOR_DEFAULT_UP); } static compensateGeometryRotation(object, direction) { CoreTransform.rotateObject(object, this.REFLECTOR_DEFAULT_UP, direction); } _onBeforeRender(renderer, scene, anyCamera) { if (!this._options.active) { return; } if (!this.renderTarget) { this._createRenderTarget(renderer); } if (!(this.renderTarget && this._coreRenderBlur)) { return; } const camera = anyCamera; this.reflectorWorldPosition.setFromMatrixPosition(this.matrixWorld); this.cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld); this.rotationMatrix.extractRotation(this.matrixWorld); this.normal.set(0, 0, 1); this.normal.applyMatrix4(this.rotationMatrix); this.view.subVectors(this.reflectorWorldPosition, this.cameraWorldPosition); if (this.view.dot(this.normal) > 0) return; this.view.reflect(this.normal).negate(); this.view.add(this.reflectorWorldPosition); this.rotationMatrix.extractRotation(camera.matrixWorld); this.lookAtPosition.set(0, 0, -1); this.lookAtPosition.applyMatrix4(this.rotationMatrix); this.lookAtPosition.add(this.cameraWorldPosition); this.target.subVectors(this.reflectorWorldPosition, this.lookAtPosition); this.target.reflect(this.normal).negate(); this.target.add(this.reflectorWorldPosition); this.virtualCamera.position.copy(this.view); this.virtualCamera.up.set(0, 1, 0); this.virtualCamera.up.applyMatrix4(this.rotationMatrix); this.virtualCamera.up.reflect(this.normal); this.virtualCamera.lookAt(this.target); this.virtualCamera.far = camera.far; this.virtualCamera.updateMatrixWorld(); this.virtualCamera.projectionMatrix.copy(camera.projectionMatrix); this.textureMatrix.set(0.5, 0, 0, 0.5, 0, 0.5, 0, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 1); this.textureMatrix.multiply(this.virtualCamera.projectionMatrix); this.textureMatrix.multiply(this.virtualCamera.matrixWorldInverse); if (this._mirrorCameraMultipliedByMatrixWorld) { this.textureMatrix.multiply(this.matrixWorld); } this.reflectorPlane.setFromNormalAndCoplanarPoint(this.normal, this.reflectorWorldPosition); this.reflectorPlane.applyMatrix4(this.virtualCamera.matrixWorldInverse); this.clipPlane.set( this.reflectorPlane.normal.x, this.reflectorPlane.normal.y, this.reflectorPlane.normal.z, this.reflectorPlane.constant ); var projectionMatrix = this.virtualCamera.projectionMatrix; this.q.x = (Math.sign(this.clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0]; this.q.y = (Math.sign(this.clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5]; this.q.z = -1; this.q.w = (1 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; this.clipPlane.multiplyScalar(2 / this.clipPlane.dot(this.q)); projectionMatrix.elements[2] = this.clipPlane.x; projectionMatrix.elements[6] = this.clipPlane.y; projectionMatrix.elements[10] = this.clipPlane.z + 1 - this._options.clipBias; projectionMatrix.elements[14] = this.clipPlane.w; this.renderTarget.texture.colorSpace = renderer.outputColorSpace; this.visible = false; var currentRenderTarget = renderer.getRenderTarget(); var currentXrEnabled = renderer.xr.enabled; var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate; renderer.xr.enabled = false; renderer.shadowMap.autoUpdate = false; renderer.setRenderTarget(this.renderTarget); renderer.state.buffers.depth.setMask(true); if (renderer.autoClear === false) renderer.clear(); renderer.render(scene, this.virtualCamera); if (isBooleanTrue(this._options.tblur)) { const blurAmount = this._options.blur * this._options.pixelRatio; const verticalBlurAmount = blurAmount * this._options.verticalBlurMult; this._coreRenderBlur.applyBlur(this.renderTarget, renderer, blurAmount, verticalBlurAmount); if (isBooleanTrue(this._options.tblur2)) { const blurAmount2 = this._options.blur2 * this._options.pixelRatio; const verticalBlurAmount2 = blurAmount2 * this._options.verticalBlur2Mult; this._coreRenderBlur.applyBlur(this.renderTarget, renderer, blurAmount2, verticalBlurAmount2); } } renderer.xr.enabled = currentXrEnabled; renderer.shadowMap.autoUpdate = currentShadowAutoUpdate; renderer.setRenderTarget(currentRenderTarget); var viewport = camera.viewport; if (viewport !== void 0) { renderer.state.viewport(viewport); } this.visible = true; } } BaseReflector.REFLECTOR_DEFAULT_UP = new Vector3(0, 0, 1);