UNPKG

@itwin/core-frontend

Version:
204 lines • 11 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * 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 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.FrustumUniforms = void 0; exports.fromSumOf = fromSumOf; const core_geometry_1 = require("@itwin/core-geometry"); const core_common_1 = require("@itwin/core-common"); const IModelFrameLifecycle_1 = require("./IModelFrameLifecycle"); const Matrix_1 = require("./Matrix"); const Sync_1 = require("./Sync"); /** Represents a Target's frustum for use in glsl as a pair of uniforms. * Do not modify fields of exposed objects directly. e.g., do not directly manipulate the projection or view matrices - use the appropriate APIs. * @internal */ class FrustumUniforms { // CPU state. Do not modify - use APIs. planFrustum = new core_common_1.Frustum(); _planFraction = 0; _nearPlaneCenter = new core_geometry_1.Point3d(); viewMatrix = core_geometry_1.Transform.createIdentity(); projectionMatrix = core_geometry_1.Matrix4d.createIdentity(); _worldUpVector = core_geometry_1.Vector3d.unitZ(); _viewUpVector = core_geometry_1.Vector3d.unitZ(); // GPU state _planeData = new Float32Array(4); _frustumData = new Float32Array(3); _worldFrustumZRange = new Float32Array(2); projectionMatrix32 = new Matrix_1.Matrix4(); _logZData = new Float32Array(2); _viewUpVector32 = new Float32Array(3); // SyncTarget syncKey = 0; // Scratch variables _scratch = { point3d: new core_geometry_1.Point3d(), vec3d: new core_geometry_1.Vector3d(), viewX: new core_geometry_1.Vector3d(), viewY: new core_geometry_1.Vector3d(), viewZ: new core_geometry_1.Vector3d(), range: new core_geometry_1.Range3d(), }; constructor() { } bindProjectionMatrix(uniform) { if (!(0, Sync_1.sync)(this, uniform)) uniform.setMatrix4(this.projectionMatrix32); } bindUpVector(uniform) { if (!(0, Sync_1.sync)(this, uniform)) uniform.setUniform3fv(this._viewUpVector32); } // uniform vec4 u_frustumPlanes; // { top, bottom, left, right } get planes() { return this._planeData; } // uniform vec3 u_frustum; // { near, far, type } get frustum() { return this._frustumData; } // uniform vec2 u_worldFrustumZRange // { min, max } get worldFrustumZRange() { return this._worldFrustumZRange; } get nearPlane() { return this._frustumData[0 /* FrustumData.kNear */]; } get farPlane() { return this._frustumData[1 /* FrustumData.kFar */]; } get type() { return this.frustum[2 /* FrustumData.kType */]; } get is2d() { return 0 /* FrustumUniformType.TwoDee */ === this.type; } get planFraction() { return this._planFraction; } // uniform vec2 u_logZ where x = 1/near and y = log(far/near) get logZ() { return this._logZData; } changeFrustum(newFrustum, newFraction, is3d) { if (newFraction === this._planFraction && is3d !== this.is2d && newFrustum.equals(this.planFrustum)) return; (0, Sync_1.desync)(this); newFrustum.clone(this.planFrustum); const range = newFrustum.toRange(this._scratch.range); this._worldFrustumZRange[0] = range.low.z; this._worldFrustumZRange[1] = range.high.z; const farLowerLeft = newFrustum.getCorner(core_common_1.Npc.LeftBottomRear); const farLowerRight = newFrustum.getCorner(core_common_1.Npc.RightBottomRear); const farUpperLeft = newFrustum.getCorner(core_common_1.Npc.LeftTopRear); const farUpperRight = newFrustum.getCorner(core_common_1.Npc.RightTopRear); const nearLowerLeft = newFrustum.getCorner(core_common_1.Npc.LeftBottomFront); const nearLowerRight = newFrustum.getCorner(core_common_1.Npc.RightBottomFront); const nearUpperLeft = newFrustum.getCorner(core_common_1.Npc.LeftTopFront); const nearUpperRight = newFrustum.getCorner(core_common_1.Npc.RightTopFront); const nearCenter = nearLowerLeft.interpolate(0.5, nearUpperRight, this._scratch.point3d); const viewX = normalizedDifference(nearLowerRight, nearLowerLeft, this._scratch.viewX); const viewY = normalizedDifference(nearUpperLeft, nearLowerLeft, this._scratch.viewY); const viewZ = viewX.crossProduct(viewY, this._scratch.viewZ).normalize(); this._planFraction = newFraction; if (!is3d || newFraction > 0.999) { // ortho or 2d const halfWidth = core_geometry_1.Vector3d.createStartEnd(farLowerRight, farLowerLeft, this._scratch.vec3d).magnitude() * 0.5; const halfHeight = core_geometry_1.Vector3d.createStartEnd(farLowerRight, farUpperRight).magnitude() * 0.5; const depth = core_geometry_1.Vector3d.createStartEnd(farLowerLeft, nearLowerLeft, this._scratch.vec3d).magnitude(); lookIn(nearCenter, viewX, viewY, viewZ, this.viewMatrix); ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, 0, depth, this.projectionMatrix); this._nearPlaneCenter.setFrom(nearLowerLeft); this._nearPlaneCenter.interpolate(0.5, nearUpperRight, this._nearPlaneCenter); this.setPlanes(halfHeight, -halfHeight, -halfWidth, halfWidth); this.setFrustum(0, depth, is3d ? 1 /* FrustumUniformType.Orthographic */ : 0 /* FrustumUniformType.TwoDee */); } else { // perspective const scale = 1.0 / (1.0 - newFraction); const zVec = core_geometry_1.Vector3d.createStartEnd(farLowerLeft, nearLowerLeft, this._scratch.vec3d); const cameraPosition = fromSumOf(farLowerLeft, zVec, scale, this._scratch.point3d); const frustumLeft = dotDifference(farLowerLeft, cameraPosition, viewX) * newFraction; const frustumRight = dotDifference(farLowerRight, cameraPosition, viewX) * newFraction; const frustumBottom = dotDifference(farLowerLeft, cameraPosition, viewY) * newFraction; const frustumTop = dotDifference(farUpperLeft, cameraPosition, viewY) * newFraction; const frustumFront = -dotDifference(nearLowerLeft, cameraPosition, viewZ); const frustumBack = -dotDifference(farLowerLeft, cameraPosition, viewZ); lookIn(cameraPosition, viewX, viewY, viewZ, this.viewMatrix); frustum(frustumLeft, frustumRight, frustumBottom, frustumTop, frustumFront, frustumBack, this.projectionMatrix); IModelFrameLifecycle_1.IModelFrameLifecycle.onChangeCameraView.raiseEvent({ cameraPosition, viewX, viewY, viewZ, }); IModelFrameLifecycle_1.IModelFrameLifecycle.onChangeCameraFrustum.raiseEvent({ type: 2 /* FrustumUniformType.Perspective */, left: frustumLeft, right: frustumRight, bottom: frustumBottom, top: frustumTop, front: frustumFront, back: frustumBack, }); this._nearPlaneCenter.setFrom(nearLowerLeft); this._nearPlaneCenter.interpolate(0.5, nearUpperRight, this._nearPlaneCenter); this.setPlanes(frustumTop, frustumBottom, frustumLeft, frustumRight); this.setFrustum(frustumFront, frustumBack, 2 /* FrustumUniformType.Perspective */); } this.viewMatrix.matrix.inverseState = core_geometry_1.InverseMatrixState.unknown; this.viewMatrix.matrix.multiplyVector(this._worldUpVector, this._viewUpVector); this._viewUpVector.normalizeInPlace(); this._viewUpVector32[0] = this._viewUpVector.x; this._viewUpVector32[1] = this._viewUpVector.y; this._viewUpVector32[2] = this._viewUpVector.z; this.projectionMatrix32.initFromMatrix4d(this.projectionMatrix); } changeProjectionMatrix(newMatrix) { (0, Sync_1.desync)(this); this.projectionMatrix.setFrom(newMatrix); this.projectionMatrix32.initFromMatrix4d(this.projectionMatrix); } setPlanes(top, bottom, left, right) { this._planeData[0 /* Plane.kTop */] = top; this._planeData[1 /* Plane.kBottom */] = bottom; this._planeData[2 /* Plane.kLeft */] = left; this._planeData[3 /* Plane.kRight */] = right; } setFrustum(nearPlane, farPlane, type) { this._frustumData[0 /* FrustumData.kNear */] = nearPlane; this._frustumData[1 /* FrustumData.kFar */] = farPlane; this._frustumData[2 /* FrustumData.kType */] = type; // If nearPlane is zero, we don't have a camera (or got very unlucky); in that case shader will compute linear depth. this._logZData[0] = 0 !== nearPlane ? 1 / nearPlane : 0; this._logZData[1] = 0 !== nearPlane ? Math.log(farPlane / nearPlane) : farPlane; } } exports.FrustumUniforms = FrustumUniforms; function normalizedDifference(p0, p1, out) { const result = undefined !== out ? out : new core_geometry_1.Vector3d(); result.x = p0.x - p1.x; result.y = p0.y - p1.y; result.z = p0.z - p1.z; result.normalizeInPlace(); return result; } /** @internal */ function fromSumOf(p, v, scale, out) { const result = undefined !== out ? out : new core_geometry_1.Point3d(); result.x = p.x + v.x * scale; result.y = p.y + v.y * scale; result.z = p.z + v.z * scale; return result; } function dotDifference(pt, origin, vec) { return (pt.x - origin.x) * vec.x + (pt.y - origin.y) * vec.y + (pt.z - origin.z) * vec.z; } function lookIn(eye, viewX, viewY, viewZ, result) { const rot = result.matrix.coffs; rot[0] = viewX.x; rot[1] = viewX.y; rot[2] = viewX.z; rot[3] = viewY.x; rot[4] = viewY.y; rot[5] = viewY.z; rot[6] = viewZ.x; rot[7] = viewZ.y; rot[8] = viewZ.z; result.origin.x = -viewX.dotProduct(eye); result.origin.y = -viewY.dotProduct(eye); result.origin.z = -viewZ.dotProduct(eye); } function ortho(left, right, bottom, top, near, far, result) { core_geometry_1.Matrix4d.createRowValues(2.0 / (right - left), 0.0, 0.0, -(right + left) / (right - left), 0.0, 2.0 / (top - bottom), 0.0, -(top + bottom) / (top - bottom), 0.0, 0.0, -2.0 / (far - near), -(far + near) / (far - near), 0.0, 0.0, 0.0, 1.0, result); } function frustum(left, right, bottom, top, near, far, result) { core_geometry_1.Matrix4d.createRowValues((2.0 * near) / (right - left), 0.0, (right + left) / (right - left), 0.0, 0.0, (2.0 * near) / (top - bottom), (top + bottom) / (top - bottom), 0.0, 0.0, 0.0, -(far + near) / (far - near), -(2.0 * far * near) / (far - near), 0.0, 0.0, -1.0, 0.0, result); } //# sourceMappingURL=FrustumUniforms.js.map