UNPKG

@itwin/core-frontend

Version:
218 lines • 9.57 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module WebGL */ import { assert, expectDefined } from "@itwin/core-bentley"; import { Matrix3d, Matrix4d, Point3d, Transform } from "@itwin/core-geometry"; import { BranchStack } from "./BranchStack"; import { BatchState } from "./BatchState"; import { Matrix3, Matrix4 } from "./Matrix"; import { RenderCommands } from "./RenderCommands"; import { desync, sync } from "./Sync"; import { ClipStack } from "./ClipStack"; import { IModelApp } from "../../../IModelApp"; function equalXYZs(a, b) { if (a === b) return true; if ((undefined === a) !== (undefined === b)) return false; if (undefined !== a && undefined !== b) return a.isExactEqual(b); assert(undefined === a && undefined === b); return true; } /** Maintains uniform variable state associated with the Branch currently being drawn by a Target. * @internal */ export class BranchUniforms { clipStack; _viewClipEnabled = false; // The model-view and model-view-projection matrices depend on the frustum. syncToken; syncKey = 0; _stack = new BranchStack(); _target; // Parameters that affect synchronization. _isInstanced = false; _viewIndependentOrigin; // CPU state _mv = Matrix4d.createIdentity(); _mvp = Matrix4d.createIdentity(); // GPU state _mv32 = new Matrix4(); _mvp32 = new Matrix4(); _m32 = new Matrix4(); _v32 = new Matrix3(); // Working state _scratchTransform = Transform.createIdentity(); _scratchTransform2 = Transform.createIdentity(); _scratchViewToWorld = Matrix3d.createIdentity(); _scratchVIModelMatrix = Transform.createIdentity(); _zeroPoint = new Point3d(0, 0, 0); get stack() { return this._stack; } constructor(target) { this._target = target; this.clipStack = new ClipStack(() => target.uniforms.frustum.viewMatrix, () => this._viewClipEnabled && this.top.viewFlags.clipVolume); } createBatchState() { return new BatchState(this._stack); } createRenderCommands(batchState) { return new RenderCommands(this._target, this._stack, batchState); } get modelViewMatrix() { return this._mv; } get top() { return this._stack.top; } get length() { return this._stack.length; } pushBranch(branch) { desync(this); this._stack.pushBranch(branch); this.setClipStyle(this.top.disableClipStyle); if (this.top.clipVolume) this.clipStack.push(this.top.clipVolume); if (branch.branch.realityModelDisplaySettings) this._target.uniforms.realityModel.update(branch.branch.realityModelDisplaySettings); } pushState(state) { desync(this); this._stack.pushState(state); if (this.top.clipVolume) this.clipStack.push(this.top.clipVolume); if (state.realityModelDisplaySettings) this._target.uniforms.realityModel.update(state.realityModelDisplaySettings); } pop() { desync(this); if (this.top.clipVolume) this.clipStack.pop(); this._stack.pop(); this.setClipStyle(this.top.disableClipStyle); } pushViewClip() { assert(!this._viewClipEnabled); this._viewClipEnabled = true; // Target.readPixels() pushes another BranchState before pushing view clip... assert((this._target.isReadPixelsInProgress ? 2 : 1) === this._stack.length); } popViewClip() { assert(this._viewClipEnabled); this._viewClipEnabled = false; assert((this._target.isReadPixelsInProgress ? 2 : 1) === this._stack.length); } changeRenderPlan(vf, is3d, hline, contourLine) { this._stack.changeRenderPlan(vf, is3d, hline, contourLine); } updateViewClip(clip, style) { this.clipStack.setViewClip(clip, style); } overrideFeatureSymbology(ovr) { this._stack.setSymbologyOverrides(ovr); } bindModelViewMatrix(uniform, geom, isViewCoords) { if (this.update(uniform, geom, isViewCoords)) uniform.setMatrix4(this._mv32); } bindModelViewProjectionMatrix(uniform, geom, isViewCoords) { if (this.update(uniform, geom, isViewCoords)) uniform.setMatrix4(this._mvp32); } bindModelToWorldTransform(uniform, geom, isViewCoords) { if (this.update(uniform, geom, isViewCoords)) uniform.setMatrix4(this._m32); } bindWorldToViewNTransform(uniform, geom, isViewCoords) { if (this.update(uniform, geom, isViewCoords)) uniform.setMatrix3(this._v32); } update(uniform, geometry, isViewCoords) { const uniforms = this._target.uniforms[isViewCoords ? "viewRect" : "frustum"]; if (!sync(uniforms, this)) desync(this); const instancedGeom = geometry.asInstanced; if (undefined !== instancedGeom || this._isInstanced) { this._isInstanced = undefined !== instancedGeom; desync(this); } const vio = geometry.viewIndependentOrigin; if (!equalXYZs(vio, this._viewIndependentOrigin)) { this._viewIndependentOrigin = vio; desync(this); } if (sync(this, uniform)) return false; let mv; const modelMatrix = this._target.currentTransform; if (isViewCoords) { // Zero out Z for silly clipping tools... mv = modelMatrix.clone(this._scratchTransform); mv.matrix.coffs[2] = mv.matrix.coffs[5] = mv.matrix.coffs[8] = 0.0; if (instancedGeom) mv = instancedGeom.getRtcModelTransform(mv); // Scale based on device-pixel ratio. const scale = this._target.devicePixelRatio; const viewMatrix = Transform.createScaleAboutPoint(this._zeroPoint, scale, this._scratchTransform2); viewMatrix.multiplyTransformTransform(mv, mv); } else { const viewMatrix = this._target.uniforms.frustum.viewMatrix; if (undefined !== instancedGeom) { // For instanced geometry, the "model view" matrix is really a transform from center of instanced geometry range to view. // Shader will compute final model-view matrix based on this and the per-instance transform. if (vio) { const viewToWorldRot = expectDefined(viewMatrix.matrix.inverse(this._scratchViewToWorld)); const rotateAboutOrigin = Transform.createFixedPointAndMatrix(vio, viewToWorldRot, this._scratchTransform2); const viModelMatrix = rotateAboutOrigin.multiplyTransformTransform(instancedGeom.getRtcModelTransform(modelMatrix), this._scratchVIModelMatrix); mv = viewMatrix.multiplyTransformTransform(viModelMatrix, this._scratchTransform); } else { mv = viewMatrix.multiplyTransformTransform(instancedGeom.getRtcModelTransform(modelMatrix), this._scratchTransform); } } else { if (undefined !== vio) { const viewToWorldRot = expectDefined(viewMatrix.matrix.inverse(this._scratchViewToWorld)); const rotateAboutOrigin = Transform.createFixedPointAndMatrix(vio, viewToWorldRot, this._scratchTransform2); const viModelMatrix = rotateAboutOrigin.multiplyTransformTransform(modelMatrix, this._scratchVIModelMatrix); mv = viewMatrix.multiplyTransformTransform(viModelMatrix, this._scratchTransform); } else { mv = viewMatrix.multiplyTransformTransform(modelMatrix, this._scratchTransform); } } } if (this._target.wantThematicDisplay) { this._m32.initFromTransform(modelMatrix); this._v32.initFromMatrix3d(this._target.uniforms.frustum.viewMatrix.matrix); } else if (undefined !== geometry.asSurface?.mesh.constantLodVParams || this._target.uniforms.batch.wantContourLines) { this._m32.initFromTransform(modelMatrix); } Matrix4d.createTransform(mv, this._mv); this._mv32.initFromTransform(mv); // Don't bother computing mvp for instanced geometry - it's not used. if (!this._isInstanced) { uniforms.projectionMatrix.multiplyMatrixMatrix(this._mv, this._mvp); this._mvp32.initFromMatrix4d(this._mvp); } return true; } // set the clip style based on disableClipStyle setClipStyle(disableClipStyle) { const vp = IModelApp.viewManager.selectedView; if (vp) { const style = vp.view.displayStyle.settings.clipStyle; this.clipStack.insideColor.alpha = disableClipStyle ? 0 : (style.insideColor ? 1 : 0); this.clipStack.outsideColor.alpha = disableClipStyle ? 0 : (style.outsideColor ? 1 : 0); this.clipStack.intersectionStyle.alpha = disableClipStyle ? 0 : (style.intersectionStyle ? style.intersectionStyle.width : 0); } } } //# sourceMappingURL=BranchUniforms.js.map