-
Notifications
You must be signed in to change notification settings - Fork 181
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
925 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
packages/frontend-2/lib/viewer/pipelines/snow/SnowFallPass.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { BaseGPass } from '@speckle/viewer' | ||
import { | ||
AdditiveBlending, | ||
type OrthographicCamera, | ||
type PerspectiveCamera, | ||
ShaderMaterial, | ||
Vector2, | ||
type WebGLRenderer | ||
} from 'three' | ||
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js' | ||
import { snowfallFrag } from './snowfallFrag' | ||
import { snowfallVert } from './snowfallVert' | ||
|
||
export class SnowFallPass extends BaseGPass { | ||
public snowfallMaterial: ShaderMaterial | ||
private fsQuad: FullScreenQuad | ||
private lastFrameTime: number = 0 | ||
private totalTime: number = 0 | ||
|
||
public constructor() { | ||
super() | ||
|
||
this.snowfallMaterial = new ShaderMaterial({ | ||
fragmentShader: snowfallFrag, | ||
vertexShader: snowfallVert, | ||
uniforms: { | ||
iTime: { value: 0 }, | ||
iResolution: { value: new Vector2(512, 512) } | ||
} | ||
}) | ||
this.snowfallMaterial.depthWrite = false | ||
this.snowfallMaterial.blending = AdditiveBlending | ||
this.snowfallMaterial.transparent = true | ||
|
||
this.fsQuad = new FullScreenQuad(this.snowfallMaterial) | ||
} | ||
|
||
public get displayName(): string { | ||
return 'SNOWFALL' | ||
} | ||
|
||
public update(_camera: PerspectiveCamera | OrthographicCamera) { | ||
if (this.lastFrameTime === 0) { | ||
this.lastFrameTime = performance.now() | ||
return | ||
} | ||
const now = performance.now() | ||
this.totalTime += now - this.lastFrameTime | ||
this.lastFrameTime = now | ||
this.snowfallMaterial.uniforms['iTime'].value = this.totalTime / 1000 | ||
this.snowfallMaterial.needsUpdate = true | ||
} | ||
|
||
public render(renderer: WebGLRenderer): boolean { | ||
if (this.onBeforeRender) this.onBeforeRender() | ||
|
||
this.fsQuad.render(renderer) | ||
if (this.onAfterRender) this.onAfterRender() | ||
return true | ||
} | ||
|
||
public setSize(width: number, height: number) { | ||
super.setSize(width, height) | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call | ||
this.snowfallMaterial.uniforms['iResolution'].value.set(width, height) | ||
this.snowfallMaterial.needsUpdate = true | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
packages/frontend-2/lib/viewer/pipelines/snow/SnowMaterial.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ | ||
import { SpeckleStandardMaterial, type SpeckleWebGLRenderer } from '@speckle/viewer' | ||
import { | ||
type MeshStandardMaterialParameters, | ||
type Scene, | ||
type Camera, | ||
type BufferGeometry, | ||
type Object3D, | ||
Box3, | ||
Vector3 | ||
} from 'three' | ||
import { objectSnowVert } from './objectSnowVert' | ||
import { objectSnowFrag } from './objectSnowFrag' | ||
|
||
class SnowMaterial extends SpeckleStandardMaterial { | ||
private minSnowValue = 0 | ||
private maxSnowValue = 0 | ||
private lastFrameTime = 0 | ||
private increaseFactor = 500000 | ||
|
||
protected get vertexProgram(): string { | ||
return objectSnowVert | ||
} | ||
|
||
protected get fragmentProgram(): string { | ||
return objectSnowFrag | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
protected get uniformsDef(): Record<string, any> { | ||
return { | ||
...super.uniformsDef, | ||
height: 1, | ||
minSnow: this.minSnowValue, | ||
maxSnow: this.maxSnowValue | ||
} | ||
} | ||
|
||
constructor(parameters: MeshStandardMaterialParameters, defines = ['USE_RTE']) { | ||
super(parameters, defines) | ||
} | ||
|
||
/** Called by three.js render loop */ | ||
public onBeforeRender( | ||
_this: SpeckleWebGLRenderer, | ||
_scene: Scene, | ||
_camera: Camera, | ||
_geometry: BufferGeometry, | ||
object: Object3D | ||
) { | ||
super.onBeforeRender(_this, _scene, _camera, _geometry, object) | ||
|
||
const sceneHeight = new Box3().setFromObject(_scene).getSize(new Vector3()) | ||
this.userData.height.value = sceneHeight.y | ||
|
||
const now = performance.now() | ||
if (this.lastFrameTime === 0) { | ||
this.lastFrameTime = now | ||
return | ||
} | ||
const delta = now - this.lastFrameTime | ||
this.lastFrameTime = now | ||
|
||
this.minSnowValue += 1 / (this.increaseFactor + delta) + 1 / this.increaseFactor | ||
this.maxSnowValue += | ||
1 / (this.increaseFactor * 0.5 + delta) + 1 / (this.increaseFactor * 0.5) | ||
|
||
this.userData.minSnow.value = Math.min(this.minSnowValue, 0.8) | ||
this.userData.maxSnow.value = Math.min(this.maxSnowValue, 0.9) | ||
|
||
this.increaseFactor -= 1000 - this.increaseFactor / 1000 | ||
this.increaseFactor = Math.max(this.increaseFactor, 5000) | ||
} | ||
} | ||
|
||
export default SnowMaterial |
148 changes: 148 additions & 0 deletions
148
packages/frontend-2/lib/viewer/pipelines/snow/SnowPipeline.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import type { | ||
SpeckleRenderer, | ||
MeshBatch, | ||
SpeckleStandardMaterial | ||
} from '@speckle/viewer' | ||
import { | ||
ProgressivePipeline, | ||
DepthPass, | ||
ObjectLayers, | ||
ObjectVisibility, | ||
ClearFlags, | ||
GeometryPass, | ||
ProgressiveAOPass, | ||
BlendPass, | ||
StencilPass, | ||
StencilMaskPass, | ||
GeometryType, | ||
Assets, | ||
AssetType | ||
} from '@speckle/viewer' | ||
import SnowMaterial from './SnowMaterial' | ||
import type SpeckleMesh from '@speckle/viewer/dist/modules/objects/SpeckleMesh' | ||
import { RepeatWrapping, NearestFilter } from 'three' | ||
import snowTex from './snow.png' | ||
import { SnowFallPass } from './SnowFallPass' | ||
|
||
export class SnowPipeline extends ProgressivePipeline { | ||
constructor(speckleRenderer: SpeckleRenderer) { | ||
super(speckleRenderer) | ||
|
||
const depthPass = new DepthPass() | ||
depthPass.setLayers([ObjectLayers.STREAM_CONTENT_MESH]) | ||
depthPass.setVisibility(ObjectVisibility.DEPTH) | ||
depthPass.setJitter(true) | ||
depthPass.setClearColor(0x000000, 1) | ||
depthPass.setClearFlags(ClearFlags.COLOR | ClearFlags.DEPTH) | ||
|
||
const opaqueColorPass = new GeometryPass() | ||
opaqueColorPass.setLayers([ | ||
ObjectLayers.STREAM_CONTENT, | ||
ObjectLayers.STREAM_CONTENT_MESH, | ||
ObjectLayers.STREAM_CONTENT_LINE, | ||
ObjectLayers.STREAM_CONTENT_POINT, | ||
ObjectLayers.STREAM_CONTENT_POINT_CLOUD, | ||
ObjectLayers.STREAM_CONTENT_TEXT | ||
]) | ||
opaqueColorPass.setVisibility(ObjectVisibility.OPAQUE) | ||
|
||
const transparentColorPass = new GeometryPass() | ||
transparentColorPass.setLayers([ | ||
ObjectLayers.STREAM_CONTENT, | ||
ObjectLayers.STREAM_CONTENT_MESH, | ||
ObjectLayers.STREAM_CONTENT_LINE, | ||
ObjectLayers.STREAM_CONTENT_POINT, | ||
ObjectLayers.STREAM_CONTENT_POINT_CLOUD, | ||
ObjectLayers.STREAM_CONTENT_TEXT, | ||
ObjectLayers.SHADOWCATCHER | ||
]) | ||
transparentColorPass.setVisibility(ObjectVisibility.TRANSPARENT) | ||
|
||
const progressiveAOPass = new ProgressiveAOPass() | ||
progressiveAOPass.setTexture('tDepth', depthPass.outputTarget?.texture) | ||
progressiveAOPass.accumulationFrames = this.accumulationFrameCount | ||
progressiveAOPass.setClearColor(0xffffff, 1) | ||
|
||
const blendPass = new BlendPass() | ||
blendPass.options = { blendAO: true, blendEdges: false } | ||
blendPass.setTexture('tAo', progressiveAOPass.outputTarget?.texture) | ||
blendPass.accumulationFrames = this.accumulationFrameCount | ||
|
||
const stencilPass = new StencilPass() | ||
stencilPass.setVisibility(ObjectVisibility.STENCIL) | ||
stencilPass.setLayers([ObjectLayers.STREAM_CONTENT_MESH]) | ||
|
||
const stencilMaskPass = new StencilMaskPass() | ||
stencilMaskPass.setVisibility(ObjectVisibility.STENCIL) | ||
stencilMaskPass.setLayers([ObjectLayers.STREAM_CONTENT_MESH]) | ||
stencilMaskPass.setClearFlags(ClearFlags.DEPTH) | ||
|
||
const overlayPass = new GeometryPass() | ||
overlayPass.setLayers([ | ||
ObjectLayers.PROPS, | ||
ObjectLayers.OVERLAY, | ||
ObjectLayers.MEASUREMENTS | ||
]) | ||
|
||
const snowfallPass = new SnowFallPass() | ||
snowfallPass.setClearColor(0x000000, 1) | ||
|
||
this.dynamicStage.push( | ||
stencilPass, | ||
opaqueColorPass, | ||
transparentColorPass, | ||
stencilMaskPass, | ||
overlayPass, | ||
snowfallPass | ||
) | ||
this.progressiveStage.push( | ||
depthPass, | ||
stencilPass, | ||
opaqueColorPass, | ||
transparentColorPass, | ||
stencilMaskPass, | ||
progressiveAOPass, | ||
blendPass, | ||
overlayPass, | ||
snowfallPass | ||
) | ||
this.passthroughStage.push( | ||
stencilPass, | ||
opaqueColorPass, | ||
transparentColorPass, | ||
stencilMaskPass, | ||
blendPass, | ||
overlayPass, | ||
snowfallPass | ||
) | ||
|
||
this.passList = this.dynamicStage | ||
} | ||
|
||
public async start() { | ||
const snowTexture = await Assets.getTexture({ | ||
id: 'snow', | ||
src: snowTex, | ||
type: AssetType.TEXTURE_8BPP | ||
}) | ||
snowTexture.wrapS = RepeatWrapping | ||
snowTexture.wrapT = RepeatWrapping | ||
snowTexture.minFilter = NearestFilter | ||
snowTexture.magFilter = NearestFilter | ||
|
||
const batches: MeshBatch[] = this.speckleRenderer.batcher.getBatches( | ||
undefined, | ||
GeometryType.MESH | ||
) | ||
|
||
for (let k = 0; k < batches.length; k++) { | ||
const batchRenderable: SpeckleMesh = batches[k].renderObject as SpeckleMesh | ||
const batchMaterial: SpeckleStandardMaterial = batches[k] | ||
.batchMaterial as SpeckleStandardMaterial | ||
const snowMaterial = new SnowMaterial({}, ['USE_RTE']) | ||
snowMaterial.copy(batchMaterial) | ||
snowMaterial.normalMap = snowTexture | ||
batchRenderable.setOverrideBatchMaterial(snowMaterial) | ||
} | ||
} | ||
} |
Oops, something went wrong.