| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- import {onChange, serialize} from 'ts-browser-helpers'
- import {
- BasicDepthPacking,
- Color,
- Euler,
- LinearFilter,
- MeshDepthMaterial,
- NoBlending,
- NoColorSpace,
- OrthographicCamera,
- RGBAFormat,
- UnsignedByteType,
- Vector3,
- WebGLRenderTarget,
- } from 'three'
- import {BaseGroundPlugin} from '../base/BaseGroundPlugin'
- import {GBufferRenderPass} from '../../postprocessing'
- import {ThreeViewer} from '../../viewer'
- import {IRenderTarget} from '../../rendering'
- import {uiPanelContainer, uiSlider, uiToggle} from 'uiconfig.js'
- import {HVBlurHelper} from '../../three/utils/HVBlurHelper'
- import {shaderReplaceString} from '../../utils'
-
- @uiPanelContainer('Contact Shadow Ground')
- export class ContactShadowGroundPlugin extends BaseGroundPlugin {
- static readonly PluginType = 'ContactShadowGroundPlugin'
-
- @uiToggle('Contact Shadows')
- @onChange(ContactShadowGroundPlugin.prototype.refresh)
- @serialize() contactShadows = true
-
- @uiSlider('Shadow Scale', [0, 2])
- @serialize()
- @onChange(ContactShadowGroundPlugin.prototype._refreshShadowCameraFrustum)
- shadowScale = 1
-
- @uiSlider('Shadow Height', [0, 20])
- @serialize()
- @onChange(ContactShadowGroundPlugin.prototype._refreshShadowCameraFrustum)
- shadowHeight = 5
-
- @uiSlider('Blur Amount', [0, 10])
- @serialize()
- @onChange(ContactShadowGroundPlugin.prototype._setDirty)
- blurAmount = 1
-
-
- shadowCamera = new OrthographicCamera(-1, 1, 1, -1, 0.001, this.shadowHeight)
- private _depthPass?: GBufferRenderPass<'contactShadowGround', WebGLRenderTarget>
- private _blurHelper?: HVBlurHelper
-
- constructor() {
- super()
- this._refreshShadowCameraFrustum = this._refreshShadowCameraFrustum.bind(this)
- this.refresh = this.refresh.bind(this)
- }
-
- onAdded(viewer: ThreeViewer): void {
- const target = viewer.renderManager.createTarget<IRenderTarget & WebGLRenderTarget>({
- 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 );',
- // 'gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * darkness );',
- )
- }
-
- this._depthPass = new GBufferRenderPass('contactShadowGround', target, material, new Color(0, 0, 0), 0)
- this._blurHelper = new HVBlurHelper(viewer)
- super.onAdded(viewer)
- }
-
- onRemove(viewer: ThreeViewer): void {
- const target = 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
-
- protected _postFrame() {
- super._postFrame()
- if (!this._viewer) return
-
- }
-
- protected _preRender() {
- super._preRender()
- if (!this._viewer || !this._depthPass || !this._blurHelper) return
-
- this._depthPass.scene = this._viewer.scene
- this._depthPass.camera = this.shadowCamera
- this._depthPass.render(this._viewer.renderManager.renderer, null)
-
- const blurTarget = this._viewer.renderManager.getTempTarget<IRenderTarget&WebGLRenderTarget>({
- 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(this._depthPass.target.texture, this._depthPass.target, blurTarget, this.blurAmount / 256)
- this._blurHelper.blur(this._depthPass.target.texture, this._depthPass.target, blurTarget, 0.4 * this.blurAmount / 256)
-
- this._viewer.renderManager.releaseTempTarget(blurTarget)
-
- }
-
- protected _refreshTransform() {
- super._refreshTransform()
-
- if (!this._mesh) return
- if (!this._viewer) return
-
- 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
- }
-
- private _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()
- }
- private _setDirty() {
- this._viewer?.setDirty()
- }
-
- protected _removeMaterial() {
- if (!this._material) return
- // todo: remove map or render target thats assigned
- super._removeMaterial()
- }
-
- public refresh(): void {
- if (!this._viewer) return
- // todo: shadow enabled check
- super.refresh()
- }
-
- protected _refreshMaterial(): boolean {
- if (!this._viewer) return false
- const isNewMaterial = super._refreshMaterial()
- if (!this._material) return isNewMaterial
- this._material.alphaMap = this._depthPass?.target.texture || null
-
- if (isNewMaterial) {
- this._material.roughness = 1
- this._material.metalness = 0
- this._material.color.set(0x111111)
- this._material.transparent = true
- this._material.userData.ssreflDisabled = true // todo: unset this in remove material.
- this._material.userData.ssreflNonPhysical = false
- // this._material.materialObject.userData.inverseAlphaMap = false // this must be false, if getting inverted colors, check clear color of gbuffer render pass.
- }
-
- return isNewMaterial
-
- }
-
- }
|