@itwin/core-frontend
Version:
iTwin.js frontend components
218 lines • 9.57 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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