Skip to content

Instantly share code, notes, and snippets.

@xeolabs
Created July 27, 2023 00:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xeolabs/742f40608fc747903ad5a2cb6390c523 to your computer and use it in GitHub Desktop.
Save xeolabs/742f40608fc747903ad5a2cb6390c523 to your computer and use it in GitHub Desktop.
import {ENTITY_FLAGS} from '../../ENTITY_FLAGS.js';
import {RENDER_PASSES} from '../../RENDER_PASSES.js';
import {math} from "../../../math/math.js";
import {RenderState} from "../../../webgl/RenderState.js";
import {geometryCompressionUtils} from "../../../math/geometryCompressionUtils.js";
import {getDataTextureRenderers} from "./TrianglesDataTextureRenderers.js";
import {TrianglesDataTextureBuffer} from "./TrianglesDataTextureBuffer.js";
import {DataTextureState} from "./DataTextureState.js"
import {DataTextureGenerator} from "./DataTextureGenerator";
import {dataTextureRamStats} from "./dataTextureRamStats";
/**
* 12-bits allowed for object ids.
*
* Limits the per-object texture height in the layer.
*/
const MAX_NUMBER_OF_OBJECTS_IN_LAYER = (1 << 16);
/**
* 4096 is max data texture height
*
* Limits the aggregated geometry texture height in the layer.
*/
const MAX_DATA_TEXTURE_HEIGHT = (1 << 12);
/**
* Align `indices` and `edgeIndices` memory layout to 8 elements.
*
* Used as an optimization for the `...portionIds...` texture, so it
* can just be stored 1 out of 8 `portionIds` corresponding to a given
* `triangle-index` or `edge-index`.
*/
const INDICES_EDGE_INDICES_ALIGNEMENT_SIZE = 8;
/**
* Number of maximum allowed per-object flags update per render frame
* before switching to batch update mode.
*/
const MAX_OBJECT_UPDATES_IN_FRAME_WITHOUT_BATCHED_UPDATE = 10;
const tempVec4a = math.vec4([0, 0, 0, 1]);
const tempVec4b = math.vec4([0, 0, 0, 1]);
const tempVec4c = math.vec4([0, 0, 0, 1]);
const tempUint8Array4 = new Uint8Array(4);
const tempFloat32Array3 = new Float32Array(3);
let _numberOfLayers = 0;
/**
* @private
*/
export class TrianglesDataTextureLayer {
constructor(model, cfg) {
this._layerNumber = _numberOfLayers++;
dataTextureRamStats.numberOfLayers++;
/**
* State sorting key.
* @type {string}
*/
this.sortId = `TrianglesDataTextureLayer-${this._layerNumber}`;
/**
* Index of this TrianglesDataTextureLayer in {@link SceneModel#_layerList}.
* @type {Number}
*/
this.layerIndex = cfg.layerIndex;
this._dataTextureRenderers = getDataTextureRenderers(model.scene);
this.model = model;
this._buffer = new TrianglesDataTextureBuffer();
/**
* @type {DataTextureState}
*/
this._dataTextureState = new DataTextureState();
/**
* @type {DataTextureGenerator}
*/
this.dataTextureGenerator = new DataTextureGenerator();
this._state = new RenderState({
origin: math.vec3(cfg.origin),
metallicRoughnessBuf: null,
positionsDecodeMatrix: math.mat4(),
textureState: this._dataTextureState,
numIndices8Bits: 0,
numIndices16Bits: 0,
numIndices32Bits: 0,
numEdgeIndices8Bits: 0,
numEdgeIndices16Bits: 0,
numEdgeIndices32Bits: 0,
numVertices: 0,
});
// These counts are used to avoid unnecessary render passes
this._numPortions = 0;
this._numVisibleLayerPortions = 0;
this._numTransparentLayerPortions = 0;
this._numXRayedLayerPortions = 0;
this._numSelectedLayerPortions = 0;
this._numHighlightedLayerPortions = 0;
this._numClippableLayerPortions = 0;
this._numEdgesLayerPortions = 0;
this._numPickableLayerPortions = 0;
this._numCulledLayerPortions = 0;
this._modelAABB = math.collapseAABB3(); // Model-space AABB
this._portions = [];
this._finalized = false;
/**
* Due to `index rebucketting` process in ```prepareMeshGeometry``` function, it's possible that a single
* portion is expanded to more than 1 real sub-portion.
*
* This Array tracks the mapping between:
*
* - external `portionIds` as seen by consumers of this class.
* - internal `sub-portionIds` actually managed by this class.
*
* The outer index of this array is the externally seen `portionId`.
* The inner value of the array, are `sub-portionIds` corresponding to the `portionId`.
*
* @type {Array<Array<int>>}
* @private
*/
this._bucketPortionIdMapping = [];
this._bucketPortionGeometries = {};
/**
* The axis-aligned World-space boundary of this TrianglesDataTextureLayer's positions.
* @type {*|Float64Array}
*/
this.aabb = math.collapseAABB3();
/**
* The number of updates in the current frame;
* @type {number}
*/
this.numUpdatesInFrame = 0;
}
/**
* Returns wheter the ```TrianglesDataTextureLayer``` has room for more portions.
*
* @param {object} cfg An object containing the geometrical data (`positions`, `indices`, `edgeIndices`) for the portion.
* @returns {Boolean} Wheter the requested portion can be created
*/
canCreatePortion(cfg) {
if (this._finalized) {
throw "Already finalized";
}
const state = this._state;
const numNewPortions = cfg.buckets.length;
if ((this._numPortions + numNewPortions) > MAX_NUMBER_OF_OBJECTS_IN_LAYER) {
dataTextureRamStats.cannotCreatePortion.because10BitsObjectId++;
}
let retVal = (this._numPortions + numNewPortions) <= MAX_NUMBER_OF_OBJECTS_IN_LAYER;
const alreadyHasPortionGeometry = cfg.geometryId && (cfg.geometryId + "#0") in this._bucketPortionGeometries;
if (!alreadyHasPortionGeometry) {
const maxIndicesOfAnyBits = Math.max(state.numIndices8Bits, state.numIndices16Bits, state.numIndices32Bits,);
let numVertices = 0;
let numIndices = 0;
cfg.buckets.forEach(bucket => {
numVertices += bucket.positionsCompressed.length / 3;
numIndices += bucket.indices.length / 3;
});
if ((state.numVertices + numVertices) > MAX_DATA_TEXTURE_HEIGHT * 4096 ||
(maxIndicesOfAnyBits + numIndices) > MAX_DATA_TEXTURE_HEIGHT * 4096) {
dataTextureRamStats.cannotCreatePortion.becauseTextureSize++;
}
retVal &&=
(state.numVertices + numVertices) <= MAX_DATA_TEXTURE_HEIGHT * 4096 &&
(maxIndicesOfAnyBits + numIndices) <= MAX_DATA_TEXTURE_HEIGHT * 4096;
}
return retVal;
}
/**
* Creates a new portion within this TrianglesDataTextureLayer, returns the new portion ID.
*
* Gives the portion the specified geometry, color and matrix.
*
* @param cfg.positions Flat float Local-space positions array.
* @param [cfg.normals] Flat float normals array.
* @param [cfg.colors] Flat float colors array.
* @param cfg.indices Flat int indices array.
* @param [cfg.edgeIndices] Flat int edges indices array.
* @param cfg.color Quantized RGB color [0..255,0..255,0..255,0..255]
* @param cfg.metallic Metalness factor [0..255]
* @param cfg.roughness Roughness factor [0..255]
* @param cfg.opacity Opacity [0..255]
* @param [cfg.meshMatrix] Flat float 4x4 matrix
* @param [cfg.worldMatrix] Flat float 4x4 matrix
* @param cfg.portionAABB Flat float AABB World-space AABB
* @param cfg.pickColor Quantized pick color
* @returns {number} Portion ID
*/
createPortion(cfg) {
if (this._finalized) {
throw "Already finalized";
}
const portionId = this._bucketPortionIdMapping.length;
const portionIdFanout = [];
this._bucketPortionIdMapping.push(portionIdFanout);
const portionAABB = cfg.portionAABB;
cfg.buckets.forEach((bucket, bucketIndex) => {
const key = `${cfg.id}#${bucketIndex}`;
let bucketPortionGeometry = this._bucketPortionGeometries[key];
if (!bucketPortionGeometry) {
bucketPortionGeometry = this._createBucketPortionGeometry(bucket);
this._bucketPortionGeometries[key] = bucketPortionGeometry;
}
const bucketPortionAABB = math.collapseAABB3();
const bucketPortionId = this._createBucketPortion(
cfg,
bucketPortionGeometry,
bucket,
// math.addVec3( instancing ? objectCfg.origin : cfg.origin, this._state.origin, math.vec3()),
bucketPortionAABB
);
math.expandAABB3(portionAABB, bucketPortionAABB);
portionIdFanout.push(bucketPortionId);
});
this.model.numPortions++;
return portionId;
}
_createBucketPortionGeometry(bucket) {
// Indices alignement
// This will make every mesh consume a multiple of INDICES_EDGE_INDICES_ALIGNEMENT_SIZE
// array items for storing the triangles of the mesh, and it supports:
// - a memory optimization of factor INDICES_EDGE_INDICES_ALIGNEMENT_SIZE
// - in exchange for a small RAM overhead
// (by adding some padding until a size that is multiple of INDICES_EDGE_INDICES_ALIGNEMENT_SIZE)
if (bucket.indices) {
const alignedIndicesLen = Math.ceil((bucket.indices.length / 3) / INDICES_EDGE_INDICES_ALIGNEMENT_SIZE) * INDICES_EDGE_INDICES_ALIGNEMENT_SIZE * 3;
dataTextureRamStats.overheadSizeAlignementIndices += 2 * (alignedIndicesLen - bucket.indices.length);
const alignedIndices = new Uint32Array(alignedIndicesLen);
alignedIndices.fill(0);
alignedIndices.set(bucket.indices);
bucket.indices = alignedIndices;
}
// EdgeIndices alignement
// This will make every mesh consume a multiple of INDICES_EDGE_INDICES_ALIGNEMENT_SIZE
// array items for storing the edges of the mesh, and it supports:
// - a memory optimization of factor INDICES_EDGE_INDICES_ALIGNEMENT_SIZE
// - in exchange for a small RAM overhead
// (by adding some padding until a size that is multiple of INDICES_EDGE_INDICES_ALIGNEMENT_SIZE)
if (bucket.edgeIndices) {
const alignedEdgeIndicesLen = Math.ceil((bucket.edgeIndices.length / 2) / INDICES_EDGE_INDICES_ALIGNEMENT_SIZE) * INDICES_EDGE_INDICES_ALIGNEMENT_SIZE * 2;
dataTextureRamStats.overheadSizeAlignementEdgeIndices += 2 * (alignedEdgeIndicesLen - bucket.edgeIndices.length);
const alignedEdgeIndices = new Uint32Array(alignedEdgeIndicesLen);
alignedEdgeIndices.fill(0);
alignedEdgeIndices.set(bucket.edgeIndices);
bucket.edgeIndices = alignedEdgeIndices;
}
const positionsCompressed = bucket.positionsCompressed;
const indices = bucket.indices;
const edgeIndices = bucket.edgeIndices;
const buffer = this._buffer;
const vertexBase = buffer.positions.length / 3;
const numVertices = positionsCompressed.length / 3;
for (let i = 0, len = positionsCompressed.length; i < len; i++) {
buffer.positions.push(positionsCompressed[i]);
}
let indicesBase;
let numTriangles = 0;
if (indices) {
numTriangles = indices.length / 3;
let indicesBuffer;
if (numVertices <= (1 << 8)) {
indicesBuffer = buffer.indices8Bits;
} else if (numVertices <= (1 << 16)) {
indicesBuffer = buffer.indices16Bits;
} else {
indicesBuffer = buffer.indices32Bits;
}
indicesBase = indicesBuffer.length / 3;
for (let i = 0, len = indices.length; i < len; i++) {
indicesBuffer.push(indices[i]);
}
}
let edgeIndicesBase;
let numEdges = 0;
if (edgeIndices) {
numEdges = edgeIndices.length / 2;
let edgeIndicesBuffer;
if (numVertices <= (1 << 8)) {
edgeIndicesBuffer = buffer.edgeIndices8Bits;
} else if (numVertices <= (1 << 16)) {
edgeIndicesBuffer = buffer.edgeIndices16Bits;
} else {
edgeIndicesBuffer = buffer.edgeIndices32Bits;
}
edgeIndicesBase = edgeIndicesBuffer.length / 2;
for (let i = 0, len = edgeIndices.length; i < len; i++) {
edgeIndicesBuffer.push(edgeIndices[i]);
}
}
this._state.numVertices += numVertices;
dataTextureRamStats.numberOfGeometries++;
return {
vertexBase,
numVertices,
numTriangles,
numEdges,
indicesBase,
edgeIndicesBase
};
}
_createBucketPortion(cfg, bucketPortionGeometry, bucket, bucketPortionAABB) {
const color = cfg.color;
const metallic = cfg.metallic;
const roughness = cfg.roughness;
const colors = cfg.colors;
const opacity = cfg.opacity;
const meshMatrix = cfg.meshMatrix;
const worldMatrix = cfg.worldMatrix;
const pickColor = cfg.pickColor;
const scene = this.model.scene;
const buffer = this._buffer;
const state = this._state;
buffer.perObjectPositionsDecodeMatrices.push(cfg.positionsDecodeMatrix);
buffer.perObjectInstancePositioningMatrices.push(meshMatrix);
// const positions = cfg.positions;
// const positionsIndex = buffer.positions.length;
// const vertsIndex = positionsIndex / 3;
// Expand the world AABB with the concrete location of the object
const localAABB = math.collapseAABB3();
math.expandAABB3Points3(localAABB, bucket.positionsCompressed);
geometryCompressionUtils.decompressAABB(localAABB, cfg.positionsDecodeMatrix);
const geometryOBB = math.AABB3ToOBB3(localAABB);
for (let i = 0, len = geometryOBB.length; i < len; i += 4) {
tempVec4a[0] = geometryOBB[i + 0];
tempVec4a[1] = geometryOBB[i + 1];
tempVec4a[2] = geometryOBB[i + 2];
math.transformPoint4(meshMatrix, tempVec4a, tempVec4b);
if (worldMatrix) {
math.transformPoint4(worldMatrix, tempVec4b, tempVec4c);
math.expandAABB3Point3(bucketPortionAABB, tempVec4c);
} else {
math.expandAABB3Point3(bucketPortionAABB, tempVec4b);
}
}
// Adjust the world AABB with the object `origin`
// if (this._state.origin) {
const origin = this._state.origin;
bucketPortionAABB[0] += origin[0];
bucketPortionAABB[1] += origin[1];
bucketPortionAABB[2] += origin[2];
bucketPortionAABB[3] += origin[0];
bucketPortionAABB[4] += origin[1];
bucketPortionAABB[5] += origin[2];
// }
math.expandAABB3(this.aabb, bucketPortionAABB);
buffer.perObjectSolid.push(cfg.solid);
if (colors) {
buffer.perObjectColors.push([colors[0] * 255, colors[1] * 255, colors[2] * 255, 255]);
} else if (color) { // Color is pre-quantized by SceneModel
buffer.perObjectColors.push([color[0], color[1], color[2], opacity]);
}
buffer.perObjectPickColors.push(pickColor);
buffer.perObjectVertexBases.push(bucketPortionGeometry.vertexBase);
{
let currentNumIndices;
if (bucketPortionGeometry.numVertices <= (1 << 8)) {
currentNumIndices = state.numIndices8Bits;
} else if (bucketPortionGeometry.numVertices <= (1 << 16)) {
currentNumIndices = state.numIndices16Bits;
} else {
currentNumIndices = state.numIndices32Bits;
}
buffer.perObjectIndexBaseOffsets.push(currentNumIndices / 3 - bucketPortionGeometry.indicesBase);
}
{
let currentNumEdgeIndices;
if (bucketPortionGeometry.numVertices <= (1 << 8)) {
currentNumEdgeIndices = state.numEdgeIndices8Bits;
} else if (bucketPortionGeometry.numVertices <= (1 << 16)) {
currentNumEdgeIndices = state.numEdgeIndices16Bits;
} else {
currentNumEdgeIndices = state.numEdgeIndices32Bits;
}
buffer.perObjectEdgeIndexBaseOffsets.push(currentNumEdgeIndices / 2 - bucketPortionGeometry.edgeIndicesBase);
}
const bucketPortionId = this._portions.length;
if (bucketPortionGeometry.numTriangles > 0) {
let numIndices = bucketPortionGeometry.numTriangles * 3;
let indicesPortionIdBuffer;
if (bucketPortionGeometry.numVertices <= (1 << 8)) {
indicesPortionIdBuffer = buffer.perTriangleNumberPortionId8Bits;
state.numIndices8Bits += numIndices;
dataTextureRamStats.totalPolygons8Bits += bucketPortionGeometry.numTriangles;
} else if (bucketPortionGeometry.numVertices <= (1 << 16)) {
indicesPortionIdBuffer = buffer.perTriangleNumberPortionId16Bits;
state.numIndices16Bits += numIndices;
dataTextureRamStats.totalPolygons16Bits += bucketPortionGeometry.numTriangles;
} else {
indicesPortionIdBuffer = buffer.perTriangleNumberPortionId32Bits;
state.numIndices32Bits += numIndices;
dataTextureRamStats.totalPolygons32Bits += bucketPortionGeometry.numTriangles;
}
dataTextureRamStats.totalPolygons += bucketPortionGeometry.numTriangles;
for (let i = 0; i < bucketPortionGeometry.numTriangles; i += INDICES_EDGE_INDICES_ALIGNEMENT_SIZE) {
indicesPortionIdBuffer.push(bucketPortionId);
}
}
if (bucketPortionGeometry.numEdges > 0) {
let numEdgeIndices = bucketPortionGeometry.numEdges * 2;
let edgeIndicesPortionIdBuffer;
if (bucketPortionGeometry.numVertices <= (1 << 8)) {
edgeIndicesPortionIdBuffer = buffer.perEdgeNumberPortionId8Bits;
state.numEdgeIndices8Bits += numEdgeIndices;
dataTextureRamStats.totalEdges8Bits += bucketPortionGeometry.numEdges;
} else if (bucketPortionGeometry.numVertices <= (1 << 16)) {
edgeIndicesPortionIdBuffer = buffer.perEdgeNumberPortionId16Bits;
state.numEdgeIndices16Bits += numEdgeIndices;
dataTextureRamStats.totalEdges16Bits += bucketPortionGeometry.numEdges;
} else {
edgeIndicesPortionIdBuffer = buffer.perEdgeNumberPortionId32Bits;
state.numEdgeIndices32Bits += numEdgeIndices;
dataTextureRamStats.totalEdges32Bits += bucketPortionGeometry.numEdges;
}
dataTextureRamStats.totalEdges += bucketPortionGeometry.numEdges;
for (let i = 0; i < bucketPortionGeometry.numEdges; i += INDICES_EDGE_INDICES_ALIGNEMENT_SIZE) {
edgeIndicesPortionIdBuffer.push(bucketPortionId);
}
}
buffer.perObjectOffsets.push([0, 0, 0]);
this._portions.push({
// vertsBase: vertsIndex,
numVertices: bucketPortionGeometry.numTriangles
});
this._numPortions++;
dataTextureRamStats.numberOfPortions++;
return bucketPortionId;
}
// updatePickCameratexture(pickViewMatrix, pickCameraMatrix) {
// this._dataTextureState.texturePickCameraMatrices.updateViewMatrix(pickViewMatrix, pickCameraMatrix);
// }
/**
* Builds data textures from the appended geometries and loads them into the GPU.
*
* No more portions can then be created.
*/
finalize() {
if (this._finalized) {
this.model.error("Already finalized");
return;
}
const state = this._state;
const textureState = this._dataTextureState;
const gl = this.model.scene.canvas.gl;
const buffer = this._buffer;
state.gl = gl;
textureState.texturePerObjectIdColorsAndFlags = this.dataTextureGenerator.generateTextureForColorsAndFlags(
gl,
buffer.perObjectColors,
buffer.perObjectPickColors,
buffer.perObjectVertexBases,
buffer.perObjectIndexBaseOffsets,
buffer.perObjectEdgeIndexBaseOffsets,
buffer.perObjectSolid
);
textureState.texturePerObjectIdOffsets = this.dataTextureGenerator.generateTextureForObjectOffsets(
gl,
this._numPortions
);
textureState.texturePerObjectIdPositionsDecodeMatrix = this.dataTextureGenerator.generateTextureForPositionsDecodeMatrices(
gl,
buffer.perObjectPositionsDecodeMatrices,
buffer.perObjectInstancePositioningMatrices
);
// position coordinates texture
textureState.texturePerVertexIdCoordinates = this.dataTextureGenerator.generateTextureForPositions(
gl,
buffer.positions
);
// portion Id triangles texture
textureState.texturePerPolygonIdPortionIds8Bits = this.dataTextureGenerator.generateTextureForPackedPortionIds(
gl,
buffer.perTriangleNumberPortionId8Bits
);
textureState.texturePerPolygonIdPortionIds16Bits = this.dataTextureGenerator.generateTextureForPackedPortionIds(
gl,
buffer.perTriangleNumberPortionId16Bits
);
textureState.texturePerPolygonIdPortionIds32Bits = this.dataTextureGenerator.generateTextureForPackedPortionIds(
gl,
buffer.perTriangleNumberPortionId32Bits
);
// portion Id texture for edges
if (buffer.perEdgeNumberPortionId8Bits.length > 0) {
textureState.texturePerEdgeIdPortionIds8Bits = this.dataTextureGenerator.generateTextureForPackedPortionIds(
gl,
buffer.perEdgeNumberPortionId8Bits
);
}
if (buffer.perEdgeNumberPortionId16Bits.length > 0) {
textureState.texturePerEdgeIdPortionIds16Bits = this.dataTextureGenerator.generateTextureForPackedPortionIds(
gl,
buffer.perEdgeNumberPortionId16Bits
);
}
if (buffer.perEdgeNumberPortionId32Bits.length > 0) {
textureState.texturePerEdgeIdPortionIds32Bits = this.dataTextureGenerator.generateTextureForPackedPortionIds(
gl,
buffer.perEdgeNumberPortionId32Bits
);
}
// indices texture
if (buffer.indices8Bits.length > 0) {
textureState.texturePerPolygonIdIndices8Bits = this.dataTextureGenerator.generateTextureFor8BitIndices(
gl,
buffer.indices8Bits
);
}
if (buffer.indices16Bits.length > 0) {
textureState.texturePerPolygonIdIndices16Bits = this.dataTextureGenerator.generateTextureFor16BitIndices(
gl,
buffer.indices16Bits
);
}
if (buffer.indices32Bits.length > 0) {
textureState.texturePerPolygonIdIndices32Bits = this.dataTextureGenerator.generateTextureFor32BitIndices(
gl,
buffer.indices32Bits
);
}
// edge indices texture
if (buffer.edgeIndices8Bits.length > 0) {
textureState.texturePerPolygonIdEdgeIndices8Bits = this.dataTextureGenerator.generateTextureFor8BitsEdgeIndices(
gl,
buffer.edgeIndices8Bits
);
}
if (buffer.edgeIndices16Bits.length > 0) {
textureState.texturePerPolygonIdEdgeIndices16Bits = this.dataTextureGenerator.generateTextureFor16BitsEdgeIndices(
gl,
buffer.edgeIndices16Bits
);
}
if (buffer.edgeIndices32Bits.length > 0) {
textureState.texturePerPolygonIdEdgeIndices32Bits = this.dataTextureGenerator.generateTextureFor32BitsEdgeIndices(
gl,
buffer.edgeIndices32Bits
);
}
// if (buffer.metallicRoughness.length > 0) {
// const metallicRoughness = new Uint8Array(buffer.metallicRoughness);
// let normalized = false;
// state.metallicRoughnessBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, metallicRoughness, buffer.metallicRoughness.length, 2, gl.STATIC_DRAW, normalized);
// }
// Model matrices texture
if (!this.model._modelMatricesTexture) {
this.model._modelMatricesTexture = this.dataTextureGenerator.generateModelTexture(
gl, this.model
);
}
textureState.textureModelMatrices = this.model._modelMatricesTexture;
// Camera textures
textureState.cameraTexture = this.dataTextureGenerator.generateCameraDataTexture(
this.model.scene.canvas.gl,
this.model.scene.camera,
this.model.scene,
this._state.origin.slice()
);
textureState.textureCameraMatrices = textureState.cameraTexture;
textureState.texturePickCameraMatrices = this.dataTextureGenerator.generatePickCameraDataTexture(
this.model.scene.canvas.gl,
this.model.scene.camera,
this._state.origin.slice()
);
textureState.finalize();
// Free up memory
this._buffer = null;
this._bucketPortionGeometries = {};
this._finalized = true;
}
attachToRenderingEvent() {
this.model.scene.on("rendering", () => {
if (this._deferredSetFlagsDirty) {
this.commitDeferredFlags();
}
this.numUpdatesInFrame = 0;
});
}
isEmpty() {
return this._numPortions === 0;
}
initFlags(portionId, flags, meshTransparent) {
if (flags & ENTITY_FLAGS.VISIBLE) {
this._numVisibleLayerPortions++;
this.model.numVisibleLayerPortions++;
}
if (flags & ENTITY_FLAGS.HIGHLIGHTED) {
this._numHighlightedLayerPortions++;
this.model.numHighlightedLayerPortions++;
}
if (flags & ENTITY_FLAGS.XRAYED) {
this._numXRayedLayerPortions++;
this.model.numXRayedLayerPortions++;
}
if (flags & ENTITY_FLAGS.SELECTED) {
this._numSelectedLayerPortions++;
this.model.numSelectedLayerPortions++;
}
if (flags & ENTITY_FLAGS.CLIPPABLE) {
this._numClippableLayerPortions++;
this.model.numClippableLayerPortions++;
}
if (flags & ENTITY_FLAGS.EDGES) {
this._numEdgesLayerPortions++;
this.model.numEdgesLayerPortions++;
}
if (flags & ENTITY_FLAGS.PICKABLE) {
this._numPickableLayerPortions++;
this.model.numPickableLayerPortions++;
}
if (flags & ENTITY_FLAGS.CULLED) {
this._numCulledLayerPortions++;
this.model.numCulledLayerPortions++;
}
if (meshTransparent) {
this._numTransparentLayerPortions++;
this.model.numTransparentLayerPortions++;
}
const deferred = true;
this._setFlags(portionId, flags, meshTransparent, deferred);
this._setFlags2(portionId, flags, deferred);
}
flushInitFlags() {
this._setDeferredFlags();
this._setDeferredFlags2();
}
setVisible(portionId, flags, transparent) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.VISIBLE) {
this._numVisibleLayerPortions++;
this.model.numVisibleLayerPortions++;
} else {
this._numVisibleLayerPortions--;
this.model.numVisibleLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
setHighlighted(portionId, flags, transparent) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.HIGHLIGHTED) {
this._numHighlightedLayerPortions++;
this.model.numHighlightedLayerPortions++;
} else {
this._numHighlightedLayerPortions--;
this.model.numHighlightedLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
setXRayed(portionId, flags, transparent) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.XRAYED) {
this._numXRayedLayerPortions++;
this.model.numXRayedLayerPortions++;
} else {
this._numXRayedLayerPortions--;
this.model.numXRayedLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
setSelected(portionId, flags, transparent) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.SELECTED) {
this._numSelectedLayerPortions++;
this.model.numSelectedLayerPortions++;
} else {
this._numSelectedLayerPortions--;
this.model.numSelectedLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
setEdges(portionId, flags, transparent) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.EDGES) {
this._numEdgesLayerPortions++;
this.model.numEdgesLayerPortions++;
} else {
this._numEdgesLayerPortions--;
this.model.numEdgesLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
setClippable(portionId, flags) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.CLIPPABLE) {
this._numClippableLayerPortions++;
this.model.numClippableLayerPortions++;
} else {
this._numClippableLayerPortions--;
this.model.numClippableLayerPortions--;
}
this._setFlags2(portionId, flags);
}
/**
* This will _start_ a "set-flags transaction".
*
* After invoking this method, calling setFlags/setFlags2 will not update
* the colors+flags texture but only store the new flags/flag2 in the
* colors+flags texture.
*
* After invoking this method, and when all desired setFlags/setFlags2 have
* been called on needed portions of the layer, invoke `commitDeferredFlags`
* to actually update the texture data.
*
* In massive "set-flags" scenarios like VFC or LOD mechanisms, the combina-
* tion of `beginDeferredFlags` + `commitDeferredFlags`brings a speed-up of
* up to 80x when e.g. objects are massively (un)culled 🚀.
*
* @private
*/
beginDeferredFlags() {
this._deferredSetFlagsActive = true;
}
/**
* This will _commit_ a "set-flags transaction".
*
* Invoking this method will update the colors+flags texture data with new
* flags/flags2 set since the previous invocation of `beginDeferredFlags`.
*
* @private
*/
commitDeferredFlags() {
this._deferredSetFlagsActive = false;
if (!this._deferredSetFlagsDirty) {
return;
}
this._deferredSetFlagsDirty = false;
const gl = this.model.scene.canvas.gl;
const textureState = this._dataTextureState;
gl.bindTexture(gl.TEXTURE_2D, textureState.texturePerObjectIdColorsAndFlags._texture);
gl.texSubImage2D(
gl.TEXTURE_2D,
0, // level
0, // xoffset
0, // yoffset
textureState.texturePerObjectIdColorsAndFlags._textureWidth, // width
textureState.texturePerObjectIdColorsAndFlags._textureHeight, // width
gl.RGBA_INTEGER,
gl.UNSIGNED_BYTE,
textureState.texturePerObjectIdColorsAndFlags._textureData
);
gl.bindTexture(gl.TEXTURE_2D, textureState.texturePerObjectIdOffsets._texture);
gl.texSubImage2D(
gl.TEXTURE_2D,
0, // level
0, // xoffset
0, // yoffset
textureState.texturePerObjectIdOffsets._textureWidth, // width
textureState.texturePerObjectIdOffsets._textureHeight, // width
gl.RGB,
gl.FLOAT,
textureState.texturePerObjectIdOffsets._textureData
);
}
setCulled(portionId, flags, transparent) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.CULLED) {
this._numCulledLayerPortions += this._bucketPortionIdMapping[portionId].length;
this.model.numCulledLayerPortions++;
} else {
this._numCulledLayerPortions -= this._bucketPortionIdMapping[portionId].length;
this.model.numCulledLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
setCollidable(portionId, flags) {
if (!this._finalized) {
throw "Not finalized";
}
}
setPickable(portionId, flags, transparent) {
if (!this._finalized) {
throw "Not finalized";
}
if (flags & ENTITY_FLAGS.PICKABLE) {
this._numPickableLayerPortions++;
this.model.numPickableLayerPortions++;
} else {
this._numPickableLayerPortions--;
this.model.numPickableLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
setColor(portionId, color) {
const subPortionMapping = this._bucketPortionIdMapping[portionId];
for (let i = 0, len = subPortionMapping.length; i < len; i++) {
this._subPortionSetColor(subPortionMapping[i], color);
}
}
_subPortionSetColor(portionId, color) {
if (!this._finalized) {
throw "Not finalized";
}
// Color
const textureState = this._dataTextureState;
const gl = this.model.scene.canvas.gl;
tempUint8Array4 [0] = color[0];
tempUint8Array4 [1] = color[1];
tempUint8Array4 [2] = color[2];
tempUint8Array4 [3] = color[3];
// object colors
textureState.texturePerObjectIdColorsAndFlags._textureData.set(tempUint8Array4, portionId * 32);
if (this._deferredSetFlagsActive) {
this._deferredSetFlagsDirty = true;
return;
}
if (++this.numUpdatesInFrame >= MAX_OBJECT_UPDATES_IN_FRAME_WITHOUT_BATCHED_UPDATE) {
this.beginDeferredFlags();
}
gl.bindTexture(gl.TEXTURE_2D, textureState.texturePerObjectIdColorsAndFlags._texture);
gl.texSubImage2D(
gl.TEXTURE_2D,
0, // level
(portionId % 512) * 8, // xoffset
Math.floor(portionId / 512), // yoffset
1, // width
1, //height
gl.RGBA_INTEGER,
gl.UNSIGNED_BYTE,
tempUint8Array4
);
// gl.bindTexture (gl.TEXTURE_2D, null);
}
setTransparent(portionId, flags, transparent) {
if (transparent) {
this._numTransparentLayerPortions++;
this.model.numTransparentLayerPortions++;
} else {
this._numTransparentLayerPortions--;
this.model.numTransparentLayerPortions--;
}
this._setFlags(portionId, flags, transparent);
}
_setFlags(portionId, flags, transparent, deferred = false) {
const subPortionMapping = this._bucketPortionIdMapping[portionId];
for (let i = 0, len = subPortionMapping.length; i < len; i++) {
this._subPortionSetFlags(subPortionMapping[i], flags, transparent);
}
}
_subPortionSetFlags(portionId, flags, transparent, deferred = false) {
if (!this._finalized) {
throw "Not finalized";
}
const visible = !!(flags & ENTITY_FLAGS.VISIBLE);
const xrayed = !!(flags & ENTITY_FLAGS.XRAYED);
const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED);
const selected = !!(flags & ENTITY_FLAGS.SELECTED);
const edges = !!(flags & ENTITY_FLAGS.EDGES);
const pickable = !!(flags & ENTITY_FLAGS.PICKABLE);
const culled = !!(flags & ENTITY_FLAGS.CULLED);
// Color
let f0;
if (!visible || culled || xrayed) { // Highlight & select are layered on top of color - not mutually exclusive
f0 = RENDER_PASSES.NOT_RENDERED;
} else {
if (transparent) {
f0 = RENDER_PASSES.COLOR_TRANSPARENT;
} else {
f0 = RENDER_PASSES.COLOR_OPAQUE;
}
}
// Silhouette
let f1;
if (!visible || culled) {
f1 = RENDER_PASSES.NOT_RENDERED;
} else if (selected) {
f1 = RENDER_PASSES.SILHOUETTE_SELECTED;
} else if (highlighted) {
f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED;
} else if (xrayed) {
f1 = RENDER_PASSES.SILHOUETTE_XRAYED;
} else {
f1 = RENDER_PASSES.NOT_RENDERED;
}
// Edges
let f2 = 0;
if (!visible || culled) {
f2 = RENDER_PASSES.NOT_RENDERED;
} else if (selected) {
f2 = RENDER_PASSES.EDGES_SELECTED;
} else if (highlighted) {
f2 = RENDER_PASSES.EDGES_HIGHLIGHTED;
} else if (xrayed) {
f2 = RENDER_PASSES.EDGES_XRAYED;
} else if (edges) {
if (transparent) {
f2 = RENDER_PASSES.EDGES_COLOR_TRANSPARENT;
} else {
f2 = RENDER_PASSES.EDGES_COLOR_OPAQUE;
}
} else {
f2 = RENDER_PASSES.NOT_RENDERED;
}
// Pick
let f3 = (visible && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED;
const textureState = this._dataTextureState;
const gl = this.model.scene.canvas.gl;
tempUint8Array4 [0] = f0;
tempUint8Array4 [1] = f1;
tempUint8Array4 [2] = f2;
tempUint8Array4 [3] = f3;
// object flags
textureState.texturePerObjectIdColorsAndFlags._textureData.set(tempUint8Array4, portionId * 32 + 8);
if (this._deferredSetFlagsActive) {
this._deferredSetFlagsDirty = true;
return;
}
if (++this.numUpdatesInFrame >= MAX_OBJECT_UPDATES_IN_FRAME_WITHOUT_BATCHED_UPDATE) {
this.beginDeferredFlags();
}
gl.bindTexture(gl.TEXTURE_2D, textureState.texturePerObjectIdColorsAndFlags._texture);
gl.texSubImage2D(
gl.TEXTURE_2D,
0, // level
(portionId % 512) * 8 + 2, // xoffset
Math.floor(portionId / 512), // yoffset
1, // width
1, //height
gl.RGBA_INTEGER,
gl.UNSIGNED_BYTE,
tempUint8Array4
);
// gl.bindTexture (gl.TEXTURE_2D, null);
}
_setDeferredFlags() {
}
_setFlags2(portionId, flags, deferred = false) {
const subPortionMapping = this._bucketPortionIdMapping[portionId];
for (let i = 0, len = subPortionMapping.length; i < len; i++) {
this._subPortionSetFlags2(subPortionMapping[i], flags);
}
}
_subPortionSetFlags2(portionId, flags, deferred = false) {
if (!this._finalized) {
throw "Not finalized";
}
const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0;
const textureState = this._dataTextureState;
const gl = this.model.scene.canvas.gl;
tempUint8Array4 [0] = clippable;
tempUint8Array4 [1] = 0;
tempUint8Array4 [2] = 1;
tempUint8Array4 [3] = 2;
// object flags2
textureState.texturePerObjectIdColorsAndFlags._textureData.set(tempUint8Array4, portionId * 32 + 12);
if (this._deferredSetFlagsActive) {
this._deferredSetFlagsDirty = true;
return;
}
if (++this.numUpdatesInFrame >= MAX_OBJECT_UPDATES_IN_FRAME_WITHOUT_BATCHED_UPDATE) {
this.beginDeferredFlags();
}
gl.bindTexture(gl.TEXTURE_2D, textureState.texturePerObjectIdColorsAndFlags._texture);
gl.texSubImage2D(
gl.TEXTURE_2D,
0, // level
(portionId % 512) * 8 + 3, // xoffset
Math.floor(portionId / 512), // yoffset
1, // width
1, //height
gl.RGBA_INTEGER,
gl.UNSIGNED_BYTE,
tempUint8Array4
);
// gl.bindTexture (gl.TEXTURE_2D, null);
}
_setDeferredFlags2() {
return;
}
setOffset(portionId, offset) {
const subPortionMapping = this._bucketPortionIdMapping[portionId];
for (let i = 0, len = subPortionMapping.length; i < len; i++) {
this._subPortionSetOffset(subPortionMapping[i], offset);
}
}
_subPortionSetOffset(portionId, offset) {
if (!this._finalized) {
throw "Not finalized";
}
// if (!this.model.scene.entityOffsetsEnabled) {
// this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled
// return;
// }
const textureState = this._dataTextureState;
const gl = this.model.scene.canvas.gl;
tempFloat32Array3 [0] = offset[0];
tempFloat32Array3 [1] = offset[1];
tempFloat32Array3 [2] = offset[2];
// object offset
textureState.texturePerObjectIdOffsets._textureData.set(tempFloat32Array3, portionId * 3);
if (this._deferredSetFlagsActive) {
this._deferredSetFlagsDirty = true;
return;
}
if (++this.numUpdatesInFrame >= MAX_OBJECT_UPDATES_IN_FRAME_WITHOUT_BATCHED_UPDATE) {
this.beginDeferredFlags();
}
gl.bindTexture(gl.TEXTURE_2D, textureState.texturePerObjectIdOffsets._texture);
gl.texSubImage2D(
gl.TEXTURE_2D,
0, // level
0, // x offset
portionId, // yoffset
1, // width
1, // height
gl.RGB,
gl.FLOAT,
tempFloat32Array3
);
// gl.bindTexture (gl.TEXTURE_2D, null);
}
// ---------------------- COLOR RENDERING -----------------------------------
drawColorOpaque(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (frameCtx.withSAO && this.model.saoEnabled) {
if (frameCtx.pbrEnabled && this.model.pbrEnabled) {
if (this._dataTextureRenderers.colorQualityRendererWithSAO) {
this._dataTextureRenderers.colorQualityRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE);
}
} else {
if (this._dataTextureRenderers.colorRendererWithSAO) {
this._dataTextureRenderers.colorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE);
}
}
} else {
if (frameCtx.pbrEnabled && this.model.pbrEnabled) {
if (this._dataTextureRenderers.colorQualityRenderer) {
this._dataTextureRenderers.colorQualityRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE);
}
} else {
if (this._dataTextureRenderers.colorRenderer) {
this._dataTextureRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE);
}
}
}
}
_updateBackfaceCull(renderFlags, frameCtx) {
const backfaces = this.model.backfaces || renderFlags.sectioned;
if (frameCtx.backfaces !== backfaces) {
const gl = frameCtx.gl;
if (backfaces) {
gl.disable(gl.CULL_FACE);
} else {
gl.enable(gl.CULL_FACE);
}
frameCtx.backfaces = backfaces;
}
}
drawColorTransparent(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (frameCtx.pbrEnabled && this.model.pbrEnabled) {
if (this._dataTextureRenderers.colorQualityRenderer) {
this._dataTextureRenderers.colorQualityRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT);
}
} else {
if (this._dataTextureRenderers.colorRenderer) {
this._dataTextureRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT);
}
}
}
// ---------------------- RENDERING SAO POST EFFECT TARGETS --------------
drawDepth(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.depthRenderer) {
this._dataTextureRenderers.depthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses depth (eg SAO) does not apply to transparent objects
}
}
drawNormals(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.normalsRenderer) {
this._dataTextureRenderers.normalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses normals (eg SAO) does not apply to transparent objects
}
}
// ---------------------- SILHOUETTE RENDERING -----------------------------------
drawSilhouetteXRayed(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.silhouetteRenderer) {
this._dataTextureRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED);
}
}
drawSilhouetteHighlighted(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.silhouetteRenderer) {
this._dataTextureRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED);
}
}
drawSilhouetteSelected(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.silhouetteRenderer) {
this._dataTextureRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED);
}
}
// ---------------------- EDGES RENDERING -----------------------------------
drawEdgesColorOpaque(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0) {
return;
}
if (this._dataTextureRenderers.edgesColorRenderer) {
this._dataTextureRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_OPAQUE);
}
}
drawEdgesColorTransparent(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0 || this._numTransparentLayerPortions === 0) {
return;
}
if (this._dataTextureRenderers.edgesColorRenderer) {
this._dataTextureRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_TRANSPARENT);
}
}
drawEdgesHighlighted(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) {
return;
}
if (this._dataTextureRenderers.edgesRenderer) {
this._dataTextureRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_HIGHLIGHTED);
}
}
drawEdgesSelected(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) {
return;
}
if (this._dataTextureRenderers.edgesRenderer) {
this._dataTextureRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_SELECTED);
}
}
drawEdgesXRayed(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) {
return;
}
if (this._dataTextureRenderers.edgesRenderer) {
this._dataTextureRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_XRAYED);
}
}
// ---------------------- OCCLUSION CULL RENDERING -----------------------------------
drawOcclusion(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.occlusionRenderer) {
this._dataTextureRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE);
}
}
// ---------------------- SHADOW BUFFER RENDERING -----------------------------------
drawShadow(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.shadowRenderer) {
this._dataTextureRenderers.shadowRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE);
}
}
//---- PICKING ----------------------------------------------------------------------------------------------------
setPickMatrices(pickViewMatrix, pickProjMatrix) {
if (this._numVisibleLayerPortions === 0) {
return;
}
this._dataTextureState.texturePickCameraMatrices.updateViewMatrix(pickViewMatrix, pickProjMatrix);
}
drawPickMesh(renderFlags, frameCtx) {
if (this._numVisibleLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.pickMeshRenderer) {
this._dataTextureRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK);
}
}
drawPickDepths(renderFlags, frameCtx) {
if (this._numVisibleLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.pickDepthRenderer) {
this._dataTextureRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK);
}
}
drawSnapDepths(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.vertexDepthRenderer) {
this._dataTextureRenderers.vertexDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK);
}
}
drawSnapInitDepthBuf(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.vertexDepthZBufferInitializer) {
this._dataTextureRenderers.vertexDepthZBufferInitializer.drawLayer(frameCtx, this, RENDER_PASSES.PICK);
}
}
drawPickNormals(renderFlags, frameCtx) {
if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) {
return;
}
this._updateBackfaceCull(renderFlags, frameCtx);
if (this._dataTextureRenderers.pickNormalsRenderer) {
this._dataTextureRenderers.pickNormalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK);
}
}
destroy() {
const state = this._state;
if (state.metallicRoughnessBuf) {
state.metallicRoughnessBuf.destroy();
state.metallicRoughnessBuf = null;
}
state.destroy();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment