@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
161 lines (160 loc) • 5.35 kB
JavaScript
"use strict";
import {
MeshDepthMaterial,
OrthographicCamera,
WebGLRenderTarget,
MeshBasicMaterial,
RepeatWrapping,
Vector3
} from "three";
import { CameraHelper } from "../helpers/CameraHelper";
import { CoreRenderBlur } from "../render/Blur";
import { isBooleanTrue } from "../Type";
function _createRenderTarget(res) {
const renderTarget = new WebGLRenderTarget(res.x, res.y);
renderTarget.texture.generateMipmaps = false;
renderTarget.texture.repeat.set(1, -1);
renderTarget.texture.wrapS = renderTarget.texture.wrapT = RepeatWrapping;
return renderTarget;
}
function _createCoreRenderBlur(res) {
return new CoreRenderBlur(res);
}
const _center = new Vector3();
const _size = new Vector3();
export class ContactShadowController {
constructor(_options) {
this._options = _options;
// hooks
this._emptyOnBeforeRender = () => {
};
this._initialVisibilityState = /* @__PURE__ */ new WeakMap();
this._includedObjects = /* @__PURE__ */ new Set();
this._mesh = this._options.mesh;
this._scene = this._options.scene.threejsScene();
this._darknessUniform = { value: this._options.darkness };
this.renderTarget = _createRenderTarget(this._options.renderTargetSize);
this._coreRenderBlur = _createCoreRenderBlur(this._options.renderTargetSize);
this._planeMaterial = new MeshBasicMaterial({
map: this.renderTarget.texture,
opacity: 1,
transparent: true,
depthWrite: false
});
this._mesh.material = this._planeMaterial;
const cameraObjects = this._createDepthCamera();
this._shadowCamera = cameraObjects.camera;
this._helper = cameraObjects.helper;
this._mesh.add(this._shadowCamera);
this._depthMaterial = this._createMaterials();
this._mesh.onBeforeRender = this.renderShadow.bind(this);
}
renderShadow(renderer, scene) {
if (this._options.showHelper) {
this._helper.update();
}
const previousOnBeforeRender = this._options.mesh.onBeforeRender;
const initialBackground = scene.background;
const helperVisible = this._helper.visible;
scene.background = null;
this._options.mesh.onBeforeRender = this._emptyOnBeforeRender;
this._helper.visible = false;
scene.overrideMaterial = this._depthMaterial;
this._initVisibility(scene);
const initialClearAlpha = renderer.getClearAlpha();
renderer.setClearAlpha(0);
renderer.setRenderTarget(this.renderTarget);
renderer.render(scene, this._shadowCamera);
this._coreRenderBlur.applyBlur(this.renderTarget, renderer, this._options.blur, this._options.blur);
if (isBooleanTrue(this._options.tblur2)) {
this._coreRenderBlur.applyBlur(this.renderTarget, renderer, this._options.blur2, this._options.blur2);
}
this._restoreVisibility(scene);
scene.overrideMaterial = null;
this._helper.visible = helperVisible;
renderer.setRenderTarget(null);
renderer.setClearAlpha(initialClearAlpha);
scene.background = initialBackground;
this._mesh.onBeforeRender = previousOnBeforeRender;
}
_createMaterials() {
const depthMaterial = new MeshDepthMaterial();
depthMaterial.onBeforeCompile = (shader) => {
shader.uniforms.darkness = this._darknessUniform;
shader.fragmentShader = /* glsl */
`
uniform float darkness;
${shader.fragmentShader.replace(
"gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );",
"gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * darkness );"
)}
`;
};
depthMaterial.depthTest = false;
depthMaterial.depthWrite = false;
return depthMaterial;
}
_createDepthCamera() {
this._mesh.geometry.computeBoundingBox();
if (this._mesh.geometry.boundingBox) {
this._mesh.geometry.boundingBox.getCenter(_center);
this._mesh.geometry.boundingBox.getSize(_size);
} else {
_center.set(0, 0, 0);
_size.set(10, 0, 10);
}
const w = _size.x;
const h = _size.z;
const dist = this._options.dist;
const camera = new OrthographicCamera();
camera.left = -w / 2;
camera.right = w / 2;
camera.bottom = -h / 2;
camera.top = h / 2;
camera.far = dist;
camera.rotation.x = Math.PI / 2;
camera.position.copy(_center);
const helper = new CameraHelper(camera);
helper.visible = this._options.showHelper;
camera.add(helper);
return { camera, helper };
}
/**
*
* VISIBILITY
*
*/
_initVisibility(scene) {
if (isBooleanTrue(this._options.renderAllObjects)) {
return;
}
this._includedObjects.clear();
this._scene.traverse((object) => {
this._initialVisibilityState.set(object, object.visible);
object.visible = false;
});
this._options.scene.objectsController.traverseObjectsWithMask(
this._options.objectsMask,
(object) => {
object.visible = true;
this._includedObjects.add(object);
},
void 0
);
this._includedObjects.forEach((object) => {
object.traverseAncestors((parent) => {
parent.visible = true;
});
});
}
_restoreVisibility(scene) {
if (isBooleanTrue(this._options.renderAllObjects)) {
return;
}
scene.traverse((object) => {
const state = this._initialVisibilityState.get(object);
if (state != null)
object.visible = state;
});
}
}