Section Capping Extension (#5209)
* feat(viewer-sandbox): Implemented section tool caps using the current viewer API meta * chore(viewer-lib): Added missing exports
This commit is contained in:
committed by
GitHub
parent
be0155a95d
commit
f2e8fb9805
@@ -0,0 +1,95 @@
|
||||
import {
|
||||
DefaultPipeline,
|
||||
Extension,
|
||||
IViewer,
|
||||
ObjectLayers,
|
||||
SectionTool,
|
||||
SectionToolEvent
|
||||
} from '@speckle/viewer'
|
||||
import {
|
||||
FrontSide,
|
||||
KeepStencilOp,
|
||||
Matrix4,
|
||||
Mesh,
|
||||
MeshBasicMaterial,
|
||||
NotEqualStencilFunc,
|
||||
Plane,
|
||||
PlaneGeometry,
|
||||
Quaternion,
|
||||
Vector3
|
||||
} from 'three'
|
||||
import { SectionCapsPipeline } from './SectionCapsPipeline'
|
||||
|
||||
export class SectionCaps extends Extension {
|
||||
protected planeMesh: Mesh
|
||||
protected _enabled = false
|
||||
|
||||
public get enabled(): boolean {
|
||||
return this._enabled
|
||||
}
|
||||
public set enabled(value: boolean) {
|
||||
this._enabled = value
|
||||
if (value) {
|
||||
this.viewer.getRenderer().pipeline = new SectionCapsPipeline(
|
||||
this.viewer.getRenderer()
|
||||
)
|
||||
} else {
|
||||
this.viewer.getRenderer().pipeline = new DefaultPipeline(
|
||||
this.viewer.getRenderer()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public get inject() {
|
||||
return [SectionTool]
|
||||
}
|
||||
|
||||
constructor(viewer: IViewer, protected sectionTool: SectionTool) {
|
||||
super(viewer)
|
||||
|
||||
this.planeMesh = new Mesh(
|
||||
new PlaneGeometry(1, 1),
|
||||
new MeshBasicMaterial({
|
||||
color: 0x047efb,
|
||||
side: FrontSide,
|
||||
stencilWrite: true,
|
||||
stencilFunc: NotEqualStencilFunc,
|
||||
stencilFail: KeepStencilOp,
|
||||
stencilZFail: KeepStencilOp,
|
||||
stencilZPass: KeepStencilOp
|
||||
})
|
||||
)
|
||||
this.planeMesh.renderOrder = 5
|
||||
this.planeMesh.layers.set(ObjectLayers.OVERLAY)
|
||||
viewer.getRenderer().scene.add(this.planeMesh)
|
||||
|
||||
this.sectionTool.on(SectionToolEvent.Updated, (planes: Plane[]) => {
|
||||
const obb = this.sectionTool.getBox()
|
||||
this.planeMesh.matrixAutoUpdate = false
|
||||
this.planeMesh.matrix.copy(
|
||||
this.getPlaneTransform(
|
||||
// Top facing plane
|
||||
planes[5],
|
||||
new Vector3(2 * obb.halfSize.x, 2 * obb.halfSize.y, 1)
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
protected getPlaneTransform(plane: Plane, scale: Vector3) {
|
||||
const obb = this.sectionTool.getBox()
|
||||
const n = plane.normal.clone().normalize().negate()
|
||||
|
||||
const up = Math.abs(n.z) < 0.999 ? new Vector3(0, 0, 1) : new Vector3(0, 1, 0)
|
||||
const t1 = new Vector3().crossVectors(up, n).normalize()
|
||||
const t2 = new Vector3().crossVectors(n, t1).normalize()
|
||||
|
||||
const basis = new Matrix4().makeBasis(t1, t2, n)
|
||||
const q = new Quaternion().setFromRotationMatrix(basis)
|
||||
const p = plane.projectPoint(obb.center.clone(), new Vector3())
|
||||
|
||||
const worldTRS = new Matrix4().compose(p, q, scale)
|
||||
|
||||
return worldTRS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
DefaultPipeline,
|
||||
ObjectLayers,
|
||||
ObjectVisibility,
|
||||
PipelineOptions,
|
||||
SpeckleRenderer
|
||||
} from '@speckle/viewer'
|
||||
import { StencilFrontPass } from './StencilFrontPass'
|
||||
import { StencilBackPass } from './StencilBackPass'
|
||||
|
||||
export class SectionCapsPipeline extends DefaultPipeline {
|
||||
constructor(speckleRenderer: SpeckleRenderer, options?: PipelineOptions) {
|
||||
super(speckleRenderer, options)
|
||||
|
||||
const stencilFrontPass = new StencilFrontPass()
|
||||
stencilFrontPass.setLayers([ObjectLayers.STREAM_CONTENT_MESH])
|
||||
stencilFrontPass.setVisibility(ObjectVisibility.OPAQUE)
|
||||
|
||||
const stencilBackPass = new StencilBackPass()
|
||||
stencilBackPass.setLayers([ObjectLayers.STREAM_CONTENT_MESH])
|
||||
stencilBackPass.setVisibility(ObjectVisibility.OPAQUE)
|
||||
|
||||
this.dynamicStage.splice(3, 0, stencilFrontPass, stencilBackPass)
|
||||
this.progressiveStage.splice(4, 0, stencilFrontPass, stencilBackPass)
|
||||
this.passthroughStage.splice(1, 0, stencilFrontPass, stencilBackPass)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { GeometryPass, SpeckleBasicMaterial } from '@speckle/viewer'
|
||||
import { BackSide, DecrementWrapStencilOp, NoBlending } from 'three'
|
||||
|
||||
export class StencilBackPass extends GeometryPass {
|
||||
private stencilBackMaterial: SpeckleBasicMaterial
|
||||
|
||||
get displayName(): string {
|
||||
return 'STENCIL-BACK'
|
||||
}
|
||||
|
||||
get overrideMaterial(): SpeckleBasicMaterial {
|
||||
return this.stencilBackMaterial
|
||||
}
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.stencilBackMaterial = new SpeckleBasicMaterial({ color: 0x0000ff }, [])
|
||||
// this.stencilBackMaterial.colorWrite = false
|
||||
this.stencilBackMaterial.depthWrite = false
|
||||
this.stencilBackMaterial.side = BackSide
|
||||
this.stencilBackMaterial.stencilWrite = true
|
||||
this.stencilBackMaterial.stencilFail = DecrementWrapStencilOp
|
||||
this.stencilBackMaterial.stencilZFail = DecrementWrapStencilOp
|
||||
this.stencilBackMaterial.stencilZPass = DecrementWrapStencilOp
|
||||
this.stencilBackMaterial.blending = NoBlending
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { GeometryPass, SpeckleBasicMaterial } from '@speckle/viewer'
|
||||
import { FrontSide, IncrementWrapStencilOp, NoBlending } from 'three'
|
||||
|
||||
export class StencilFrontPass extends GeometryPass {
|
||||
private stencilFrontMaterial: SpeckleBasicMaterial
|
||||
|
||||
get displayName(): string {
|
||||
return 'STENCIL-FRONT'
|
||||
}
|
||||
|
||||
get overrideMaterial(): SpeckleBasicMaterial {
|
||||
return this.stencilFrontMaterial
|
||||
}
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.stencilFrontMaterial = new SpeckleBasicMaterial({ color: 0xff0000 }, [])
|
||||
this.stencilFrontMaterial.side = FrontSide
|
||||
this.stencilFrontMaterial.stencilWrite = true
|
||||
this.stencilFrontMaterial.stencilFail = IncrementWrapStencilOp
|
||||
this.stencilFrontMaterial.stencilZFail = IncrementWrapStencilOp
|
||||
this.stencilFrontMaterial.stencilZPass = IncrementWrapStencilOp
|
||||
this.stencilFrontMaterial.blending = NoBlending
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ import {
|
||||
ObjectLoader2Flags,
|
||||
ObjectLoader2Factory
|
||||
} from '@speckle/objectloader2'
|
||||
import { SectionCaps } from './Extensions/SectionCaps.ts/SectionCaps'
|
||||
|
||||
export default class Sandbox {
|
||||
private viewer: Viewer
|
||||
@@ -433,6 +434,8 @@ export default class Sandbox {
|
||||
}
|
||||
this.viewer.getExtension(SectionTool).setBox(box)
|
||||
this.viewer.getExtension(SectionTool).toggle()
|
||||
const sectionCaps = this.viewer.getExtension(SectionCaps)
|
||||
if (sectionCaps) sectionCaps.enabled = !sectionCaps.enabled
|
||||
})
|
||||
|
||||
const toggleSectionBoxVisibility = this.tabs.pages[0].addButton({
|
||||
|
||||
@@ -56,6 +56,7 @@ const createViewer = async (containerName: string, _stream: string) => {
|
||||
const boxSelect = viewer.createExtension(BoxSelection)
|
||||
boxSelect.realtimeSelection = false
|
||||
viewer.createExtension(PassReader)
|
||||
// viewer.createExtension(SectionCaps)
|
||||
|
||||
const sandbox = new Sandbox(controlsContainer, viewer, multiSelectList)
|
||||
|
||||
|
||||
@@ -114,6 +114,8 @@ import {
|
||||
ProgressiveGPass
|
||||
} from './modules/pipeline/Passes/GPass.js'
|
||||
import {
|
||||
PipelineOptions,
|
||||
BasePipelineOptions,
|
||||
DefaultPipelineOptions,
|
||||
Pipeline
|
||||
} from './modules/pipeline/Pipelines/Pipeline.js'
|
||||
@@ -283,6 +285,8 @@ export {
|
||||
ArcticViewPipeline,
|
||||
TAAPipeline,
|
||||
ShadedViewPipeline,
|
||||
PipelineOptions,
|
||||
BasePipelineOptions,
|
||||
DefaultPipelineOptions,
|
||||
DefaultEdgesPipelineOptions,
|
||||
ViewModes,
|
||||
|
||||
Reference in New Issue
Block a user