UNPKG

threepipe

Version:

A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.

203 lines 8.82 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { getOrCall, onChange, serialize } from 'ts-browser-helpers'; import { BasicDepthPacking, Color, Euler, LinearFilter, MeshDepthMaterial, NoBlending, NoColorSpace, OrthographicCamera, RGBAFormat, UnsignedByteType, Vector3, } from 'three'; import { BaseGroundPlugin } from '../base/BaseGroundPlugin'; import { GBufferRenderPass } from '../../postprocessing'; import { uiPanelContainer, uiSlider, uiToggle } from 'uiconfig.js'; import { HVBlurHelper } from '../../three/utils/HVBlurHelper'; import { shaderReplaceString } from '../../utils'; let ContactShadowGroundPlugin = class ContactShadowGroundPlugin extends BaseGroundPlugin { constructor() { super(); this.contactShadows = true; this.shadowScale = 1; this.shadowHeight = 5; this.blurAmount = 1; this.shadowCamera = new OrthographicCamera(-1, 1, 1, -1, 0.001, this.shadowHeight); this._depthTex = null; this._refreshShadowCameraFrustum = this._refreshShadowCameraFrustum.bind(this); this.refresh = this.refresh.bind(this); } onAdded(viewer) { const target = viewer.renderManager.createTarget({ type: UnsignedByteType, format: RGBAFormat, colorSpace: NoColorSpace, size: { width: 512, height: 512 }, generateMipmaps: false, depthBuffer: true, minFilter: LinearFilter, magFilter: LinearFilter, // isAntialiased: this._viewer.isAntialiased, }); target.texture.name = 'groundContactDepthTexture'; // https://github.com/mrdoob/three.js/blob/master/examples/webgl_shadow_contact.html const material = new MeshDepthMaterial({ // depthPacking: RGBADepthPacking, // todo depthPacking: BasicDepthPacking, transparent: false, blending: NoBlending, }); material.onBeforeCompile = (shader) => { shader.uniforms.opacity.value = 1.; shader.fragmentShader = shaderReplaceString(shader.fragmentShader, 'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );', 'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), 1.0 );'); }; this._depthPass = new GBufferRenderPass('contactShadowGround', target, material, new Color(0, 0, 0), 0); this._blurHelper = new HVBlurHelper(viewer); super.onAdded(viewer); } onRemove(viewer) { const target = getOrCall(this._depthPass?.target); if (target) this._viewer?.renderManager.disposeTarget(target); this._depthPass?.dispose(); this._depthPass = undefined; this._blurHelper?.dispose(); this._blurHelper = undefined; return super.onRemove(viewer); } // todo: dispose target, material, pass and stuff _postFrame() { super._postFrame(); if (!this._viewer) return; } _preRender() { super._preRender(); if (!this._viewer || !this._depthPass || !this._blurHelper || !this.contactShadows || !this.visible) return; this._depthPass.scene = this._viewer.scene; this._depthPass.camera = this.shadowCamera; this._depthPass.render(this._viewer.renderManager.renderer, null); const target = getOrCall(this._depthPass.target); if (!target) return; const blurTarget = this._viewer.renderManager.getTempTarget({ type: UnsignedByteType, format: RGBAFormat, colorSpace: NoColorSpace, size: { width: 1024, height: 1024 }, generateMipmaps: false, depthBuffer: false, minFilter: LinearFilter, magFilter: LinearFilter, // isAntialiased: this._viewer.isAntialiased, }); this._blurHelper.blur(target.texture, target, blurTarget, this.blurAmount / 256); this._blurHelper.blur(target.texture, target, blurTarget, 0.4 * this.blurAmount / 256); this._viewer.renderManager.releaseTempTarget(blurTarget); } _refreshTransform() { if (!super._refreshTransform()) return false; if (!this._mesh) return false; if (!this._viewer) return false; this.shadowCamera.position.copy(this._mesh.getWorldPosition(new Vector3())); this.shadowCamera.setRotationFromEuler(new Euler(Math.PI / 2., 0, 0)); this.shadowCamera.updateMatrixWorld(); this._refreshShadowCameraFrustum(); this._mesh.scale.y = -this.size; return true; } _refreshShadowCameraFrustum() { if (!this.shadowCamera) return; this.shadowCamera.left = -this.size / (2 * this.shadowScale); this.shadowCamera.right = this.size / (2 * this.shadowScale); this.shadowCamera.top = this.size / (2 * this.shadowScale); this.shadowCamera.bottom = -this.size / (2 * this.shadowScale); this.shadowCamera.far = this.shadowHeight; this.shadowCamera.updateProjectionMatrix(); this._setDirty(); } _setDirty() { this._viewer?.setDirty(); } _removeMaterial() { if (!this._material) return; this._material.alphaMap = null; if (this._material.userData.ssreflDisabled) delete this._material.userData.ssreflDisabled; if (this._material.userData.ssreflNonPhysical) delete this._material.userData.ssreflNonPhysical; super._removeMaterial(); } refresh() { if (!this._viewer) return; if (!this.contactShadows) { if (this._material?.alphaMap === this._depthTex) { this._material.alphaMap = null; this._material.setDirty(); } if (this._material?.userData.__csgpParamsSet) { delete this._material.userData.__csgpParamsSet; delete this._material.userData.ssreflDisabled; delete this._material.userData.ssreflNonPhysical; } this._depthTex = null; } else { this._depthTex = getOrCall(this._depthPass?.target)?.texture || null; } super.refresh(); } _createMaterial(material) { const mat = super._createMaterial(material); mat.roughness = 1; mat.metalness = 0; mat.color.set(0x111111); mat.transparent = true; // mat.userData.inverseAlphaMap = false // this must be false, if getting inverted colors, check clear color of gbuffer render pass. return mat; } _refreshMaterial() { if (!this._viewer) return false; const isNewMaterial = super._refreshMaterial(); if (!this._material) return isNewMaterial; if (this.contactShadows) { this._material.userData.ssreflDisabled = true; this._material.userData.ssreflNonPhysical = false; this._material.userData.__csgpParamsSet = true; this._material.alphaMap = this._depthTex || null; this._material.setDirty(); } return isNewMaterial; } }; ContactShadowGroundPlugin.PluginType = 'ContactShadowGroundPlugin'; __decorate([ uiToggle('Contact Shadows'), onChange(ContactShadowGroundPlugin.prototype.refresh), serialize() ], ContactShadowGroundPlugin.prototype, "contactShadows", void 0); __decorate([ uiSlider('Shadow Scale', [0, 2]), serialize(), onChange(ContactShadowGroundPlugin.prototype._refreshShadowCameraFrustum) ], ContactShadowGroundPlugin.prototype, "shadowScale", void 0); __decorate([ uiSlider('Shadow Height', [0, 20]), serialize(), onChange(ContactShadowGroundPlugin.prototype._refreshShadowCameraFrustum) ], ContactShadowGroundPlugin.prototype, "shadowHeight", void 0); __decorate([ uiSlider('Blur Amount', [0, 10]), serialize(), onChange(ContactShadowGroundPlugin.prototype._setDirty) ], ContactShadowGroundPlugin.prototype, "blurAmount", void 0); ContactShadowGroundPlugin = __decorate([ uiPanelContainer('Contact Shadow Ground') ], ContactShadowGroundPlugin); export { ContactShadowGroundPlugin }; //# sourceMappingURL=ContactShadowGroundPlugin.js.map