@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
194 lines (193 loc) • 7.98 kB
JavaScript
"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);