Reference Source

src/viewer/scene/webgl/FrameContext.js

import {math} from "../math/math.js";
import {createRTCViewMat} from "../math/rtcCoords.js";

/**
 * @desc Provides rendering context to {@link Drawable"}s as xeokit renders them for a frame.
 *
 * Also creates RTC viewing and picking matrices, caching and reusing matrices within each frame.
 *
 * @private
 */
class FrameContext {

    constructor(scene) {

        this._scene = scene;

        this._matPool = [];
        this._matPoolNextFreeIndex = 0;

        this._rtcViewMats = {};
        this._rtcPickViewMats = {};

        this.reset();
    }

    /**
     * Called by the renderer before each frame.
     * @private
     */
    reset() {

        this._matPoolNextFreeIndex = 0;
        this._rtcViewMats = {};
        this._rtcPickViewMats = {};

        /**
         * The WebGL rendering context.
         * @type {WebGLRenderingContext}
         */
        this.gl = this._scene.canvas.gl;

        /**
         * ID of the last {@link WebGLProgram} that was bound during the current frame.
         * @property lastProgramId
         * @type {Number}
         */
        this.lastProgramId = null;

        /**
         * Whether to render a physically-based representation for triangle surfaces.
         *
         * When ````false````, we'll render them with a fast vertex-shaded Gouraud-shaded representation, which
         * is great for zillions of objects.
         *
         * When ````true````, we'll render them at a better visual quality, using smooth, per-fragment shading
         * and a more realistic lighting model.
         *
         * @property quality
         * @default false
         * @type {Boolean}
         */
        this.pbrEnabled = false;

        /**
         * Whether to render color textures for triangle surfaces.
         *
         * @property quality
         * @default false
         * @type {Boolean}
         */
        this.colorTextureEnabled = false;

        /**
         * Whether SAO is currently enabled during the current frame.
         * @property withSAO
         * @default false
         * @type {Boolean}
         */
        this.withSAO = false;

        /**
         * Whether backfaces are currently enabled during the current frame.
         * @property backfaces
         * @default false
         * @type {Boolean}
         */
        this.backfaces = false;

        /**
         * The vertex winding order for what we currently consider to be a backface during current
         * frame: true == "cw", false == "ccw".
         * @property frontFace
         * @default true
         * @type {Boolean}
         */
        this.frontface = true;

        /**
         * The next available texture unit to bind a {@link Texture} to.
         * @defauilt 0
         * @property textureUnit
         * @type {number}
         */
        this.textureUnit = 0;

        /**
         * Performance statistic that counts how many times the renderer has called ````gl.drawElements()```` has been
         * called so far within the current frame.
         * @default 0
         * @property drawElements
         * @type {number}
         */
        this.drawElements = 0;

        /**
         * Performance statistic that counts how many times ````gl.drawArrays()```` has been called so far within
         * the current frame.
         * @default 0
         * @property drawArrays
         * @type {number}
         */
        this.drawArrays = 0;

        /**
         * Performance statistic that counts how many times ````gl.useProgram()```` has been called so far within
         * the current frame.
         * @default 0
         * @property useProgram
         * @type {number}
         */
        this.useProgram = 0;

        /**
         * Statistic that counts how many times ````gl.bindTexture()```` has been called so far within the current frame.
         * @default 0
         * @property bindTexture
         * @type {number}
         */
        this.bindTexture = 0;

        /**
         * Counts how many times the renderer has called ````gl.bindArray()```` so far within the current frame.
         * @defaulr 0
         * @property bindArray
         * @type {number}
         */
        this.bindArray = 0;

        /**
         * Indicates which pass the renderer is currently rendering.
         *
         * See {@link Scene/passes:property"}}Scene#passes{{/crossLink}}, which configures how many passes we render
         * per frame, which typically set to ````2```` when rendering a stereo view.
         *
         * @property pass
         * @type {number}
         */
        this.pass = 0;

        /**
         * The 4x4 viewing transform matrix the renderer is currently using when rendering castsShadows.
         *
         * This sets the viewpoint to look from the point of view of each {@link DirLight}
         * or {@link PointLight} that casts a shadow.
         *
         * @property shadowViewMatrix
         * @type {Number[]}
         */
        this.shadowViewMatrix = null;

        /**
         * The 4x4 viewing projection matrix the renderer is currently using when rendering shadows.
         *
         * @property shadowProjMatrix
         * @type {Number[]}
         */
        this.shadowProjMatrix = null;

        /**
         * The 4x4 viewing transform matrix the renderer is currently using when rendering a ray-pick.
         *
         * This sets the viewpoint to look along the ray given to {@link Scene/pick:method"}}Scene#pick(){{/crossLink}}
         * when picking with a ray.
         *
         * @property pickViewMatrix
         * @type {Number[]}
         */
        this.pickViewMatrix = null;

        /**
         * The 4x4 orthographic projection transform matrix the renderer is currently using when rendering a ray-pick.
         *
         * @property pickProjMatrix
         * @type {Number[]}
         */
        this.pickProjMatrix = null;

        /**
         * Distance to the near clipping plane when rendering depth fragments for GPU-accelerated 3D picking.
         *
         * @property pickZNear
         * @type {Number|*}
         */
        this.pickZNear = 0.01;

        /**
         * Distance to the far clipping plane when rendering depth fragments for GPU-accelerated 3D picking.
         *
         * @property pickZFar
         * @type {Number|*}
         */
        this.pickZFar = 5000;

        /**
         * Whether or not the renderer is currently picking invisible objects.
         *
         * @property pickInvisible
         * @type {Number}
         */
        this.pickInvisible = false;

        /**
         * Used to draw only requested elements / indices.
         *
         * @property pickElementsCount
         * @type {Number}
         */
        this.pickElementsCount = null;

        /**
         * Used to draw only requested elements / indices.
         *
         * @property pickElementsOffset
         * @type {Number}
         */
        this.pickElementsOffset = null;

        /** The current line width.
         *
         * @property lineWidth
         * @type Number
         */
        this.lineWidth = 1;

        /**
         * Collects info from SceneModel.drawSnapInit and SceneModel.drawSnap,
         * which is then used in Renderer to determine snap-picking results.
         *
         * @type {{}}
         */
        this.snapPickLayerParams = {};

        /**
         * Collects info from SceneModel.drawSnapInit and SceneModel.drawSnap,
         * which is then used in Renderer to determine snap-picking results.
         * @type {number}
         */
        this.snapPickLayerNumber = 0;

        /**
         * Collects info from SceneModel.drawSnapInit and SceneModel.drawSnap,
         * which is then used in Renderer to determine snap-picking results.
         * @type {Number[]}
         */
        this.snapPickCoordinateScale = math.vec3();

        /**
         * Collects info from SceneModel.drawSnapInit and SceneModel.drawSnap,
         * which is then used in Renderer to determine snap-picking results.
         * @type {Number[]}
         */
        this.snapPickOrigin = math.vec3();
    }

    /**
     * Get View matrix for the given RTC center.
     */
    getRTCViewMatrix(originHash, origin) {
        let rtcViewMat = this._rtcViewMats[originHash];
        if (!rtcViewMat) {
            rtcViewMat = this._getNewMat();
            createRTCViewMat(this._scene.camera.viewMatrix, origin, rtcViewMat);
            this._rtcViewMats[originHash] = rtcViewMat;
        }
        return rtcViewMat;
    }

    /**
     * Get picking View RTC matrix for the given RTC center.
     */
    getRTCPickViewMatrix(originHash, origin) {
        let rtcPickViewMat = this._rtcPickViewMats[originHash];
        if (!rtcPickViewMat) {
            rtcPickViewMat = this._getNewMat();
            const pickViewMat = this.pickViewMatrix || this._scene.camera.viewMatrix;
            createRTCViewMat(pickViewMat, origin, rtcPickViewMat);
            this._rtcPickViewMats[originHash] = rtcPickViewMat;
        }
        return rtcPickViewMat;
    }

    _getNewMat() {
        let mat = this._matPool[this._matPoolNextFreeIndex];
        if (!mat) {
            mat = math.mat4();
            this._matPool[this._matPoolNextFreeIndex] = mat;
        }
        this._matPoolNextFreeIndex++;
        return mat;
    }
}

export {FrameContext};