UNPKG

@polygonjs/polygonjs

Version:

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

161 lines (160 loc) 5.35 kB
"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; }); } }