From 0d6e5e1a6396ac4c8791d6352470014c05f9d894 Mon Sep 17 00:00:00 2001 From: Ib Green Date: Tue, 20 Aug 2019 05:48:31 -0700 Subject: [PATCH 1/3] 3d-tiles: Optimize quantized positions by using normalized shorts and model matrix adjustments --- .../helpers/normalize-3d-tile-positions.js | 59 +++++++++++++------ .../src/parsers/parse-3d-tile-point-cloud.js | 20 +++---- .../src/tileset/helpers/transform-utils.js | 6 ++ 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js b/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js index 464a90c48f..c8ee6dbda5 100644 --- a/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js +++ b/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js @@ -1,24 +1,47 @@ -import {Vector3} from 'math.gl'; +import { Vector3 } from 'math.gl'; +import { GL } from '@loaders.gl/math'; -const scratchPosition = new Vector3(); +// Prepare attribute for positions +// For quantized posititions, either expand to Float32Array or return custom accessor +// https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/Instanced3DModel/README.md#quantized-positions -export function normalize3DTilePositionAttribute(tile, positions) { - if (tile.isQuantized) { - // https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/Instanced3DModel/README.md#quantized-positions +export function normalize3DTilePositionAttribute(tile, positions, options) { + if (!tile.isQuantized) { + return positions; + } + + // Optionally decode quantized positions on GPU, for renderers that can't work with normalized attributes + if (options.decodeQuantizedPositions) { + tile.isQuantized = false; + return decodeQuantizedPositions(tile, positions); + } + + // Use normalized shorts directly, no copying/processing. + // NOTE: The "missing" offset/scaling operations are automatically added to modelMatrix if `tile.isQuantized === true` + return { + type: GL.UNSIGNED_SHORT, + value: positions, + size: 3, + normalized: true + }; +} + +// Pre-scale quantized positions on CPU +function decodeQuantizedPositions(tile, positions) { + const scratchPosition = new Vector3(); + const decodedArray = new Float32Array(tile.pointCount * 3); + + for (let i = 0; i < tile.pointCount; i++) { // POSITION_QUANTIZED * QUANTIZED_VOLUME_SCALE / 65535.0 + QUANTIZED_VOLUME_OFFSET - const decodedArray = new Float32Array(tile.pointCount * 3); - for (let i = 0; i < tile.pointCount; i++) { - scratchPosition - .set(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]) - .multiply(tile.quantizedVolumeScale) - .scale(1 / tile.quantizedRange) - .add(tile.quantizedVolumeOffset); - - scratchPosition.toArray(decodedArray, i * 3); - } - - return decodedArray; + scratchPosition + .set(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]) + // TODO - Remove this when deck.gl allows `normalized` flag to be set on `positions` + .scale(1 / tile.quantizedRange) + .multiply(tile.quantizedVolumeScale) + .add(tile.quantizedVolumeOffset); + + scratchPosition.toArray(decodedArray, i * 3); } - return positions; + return decodedArray; } diff --git a/modules/3d-tiles/src/parsers/parse-3d-tile-point-cloud.js b/modules/3d-tiles/src/parsers/parse-3d-tile-point-cloud.js index d65a9d4bd8..1383a5add4 100644 --- a/modules/3d-tiles/src/parsers/parse-3d-tile-point-cloud.js +++ b/modules/3d-tiles/src/parsers/parse-3d-tile-point-cloud.js @@ -29,7 +29,7 @@ export function parsePointCloud3DTileSync(tile, arrayBuffer, byteOffset, options byteOffset = parse3DTileTablesHeaderSync(tile, arrayBuffer, byteOffset, options); byteOffset = parse3DTileTablesSync(tile, arrayBuffer, byteOffset, options); - extractPointCloudSync(tile); + extractPointCloudSync(tile, options); return byteOffset; } @@ -42,19 +42,19 @@ async function extractPointCloud(tile, options) { await parseDraco(tile, featureTable, batchTable, options); - parsePositions(tile, featureTable); - parseColors(tile, featureTable, batchTable); - parseNormals(tile, featureTable); + parsePositions(tile, featureTable, options); + parseColors(tile, featureTable, batchTable, options); + parseNormals(tile, featureTable, options); } -function extractPointCloudSync(tile) { +function extractPointCloudSync(tile, options) { initializeTile(tile); const {featureTable} = parsePointCloudTables(tile); - parsePositions(tile, featureTable); - parseColors(tile, featureTable); - parseNormals(tile, featureTable); + parsePositions(tile, featureTable, options); + parseColors(tile, featureTable, options); + parseNormals(tile, featureTable, options); } function initializeTile(tile) { @@ -91,7 +91,7 @@ function parsePointCloudTables(tile) { return {featureTable, batchTable}; } -function parsePositions(tile, featureTable) { +function parsePositions(tile, featureTable, options) { if (!tile.attributes.positions) { if (featureTable.hasProperty('POSITION')) { tile.attributes.positions = featureTable.getPropertyArray('POSITION', GL.FLOAT, 3); @@ -119,7 +119,7 @@ function parsePositions(tile, featureTable) { throw new Error('QUANTIZED_VOLUME_OFFSET must be defined for quantized positions.'); } - tile.attributes.positions = normalize3DTilePositionAttribute(tile, positions); + tile.attributes.positions = normalize3DTilePositionAttribute(tile, positions, options); } } diff --git a/modules/3d-tiles/src/tileset/helpers/transform-utils.js b/modules/3d-tiles/src/tileset/helpers/transform-utils.js index cd91dbc499..2cfbb7aa9b 100644 --- a/modules/3d-tiles/src/tileset/helpers/transform-utils.js +++ b/modules/3d-tiles/src/tileset/helpers/transform-utils.js @@ -25,6 +25,12 @@ export function calculateTransformProps(tileHeader, tile) { modelMatrix.translate(rtcCenter); } + if (tile.isQuantized) { + modelMatrix + .translate(tile.quantizedVolumeOffset) + .scale(tile.quantizedVolumeScale); + } + tile.cartesianOrigin = cartesianOrigin; tile.cartographicOrigin = cartographicOrigin; tile.modelMatrix = modelMatrix; From a97b65ee6f32007692b1ae1ce093def1ba43dc51 Mon Sep 17 00:00:00 2001 From: Ib Green Date: Thu, 29 Aug 2019 19:31:55 -0700 Subject: [PATCH 2/3] prettier --- .../src/parsers/helpers/normalize-3d-tile-positions.js | 4 ++-- modules/3d-tiles/src/tileset/helpers/transform-utils.js | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js b/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js index c8ee6dbda5..3185c700b9 100644 --- a/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js +++ b/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js @@ -1,5 +1,5 @@ -import { Vector3 } from 'math.gl'; -import { GL } from '@loaders.gl/math'; +import {Vector3} from 'math.gl'; +import {GL} from '@loaders.gl/math'; // Prepare attribute for positions // For quantized posititions, either expand to Float32Array or return custom accessor diff --git a/modules/3d-tiles/src/tileset/helpers/transform-utils.js b/modules/3d-tiles/src/tileset/helpers/transform-utils.js index 2cfbb7aa9b..0b9df0c0a0 100644 --- a/modules/3d-tiles/src/tileset/helpers/transform-utils.js +++ b/modules/3d-tiles/src/tileset/helpers/transform-utils.js @@ -26,9 +26,7 @@ export function calculateTransformProps(tileHeader, tile) { } if (tile.isQuantized) { - modelMatrix - .translate(tile.quantizedVolumeOffset) - .scale(tile.quantizedVolumeScale); + modelMatrix.translate(tile.quantizedVolumeOffset).scale(tile.quantizedVolumeScale); } tile.cartesianOrigin = cartesianOrigin; From 9efd9f2e3b484bfeb64b026a93cfbf6a8f2660c8 Mon Sep 17 00:00:00 2001 From: Ib Green Date: Fri, 30 Aug 2019 08:27:25 -0700 Subject: [PATCH 3/3] Address commnents --- .../helpers/normalize-3d-tile-positions.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js b/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js index 3185c700b9..3947ec612b 100644 --- a/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js +++ b/modules/3d-tiles/src/parsers/helpers/normalize-3d-tile-positions.js @@ -2,21 +2,21 @@ import {Vector3} from 'math.gl'; import {GL} from '@loaders.gl/math'; // Prepare attribute for positions -// For quantized posititions, either expand to Float32Array or return custom accessor -// https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/Instanced3DModel/README.md#quantized-positions - export function normalize3DTilePositionAttribute(tile, positions, options) { if (!tile.isQuantized) { return positions; } - // Optionally decode quantized positions on GPU, for renderers that can't work with normalized attributes + // For quantized posititions, either expand to Float32Array or return custom accessor + // https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/Instanced3DModel/README.md#quantized-positions + + // Optionally decodes quantized positions on GPU, for simpler renderers that don't accept normalized attributes if (options.decodeQuantizedPositions) { tile.isQuantized = false; return decodeQuantizedPositions(tile, positions); } - // Use normalized shorts directly, no copying/processing. + // Default: Use normalized shorts directly, no copying/processing. // NOTE: The "missing" offset/scaling operations are automatically added to modelMatrix if `tile.isQuantized === true` return { type: GL.UNSIGNED_SHORT, @@ -32,15 +32,13 @@ function decodeQuantizedPositions(tile, positions) { const decodedArray = new Float32Array(tile.pointCount * 3); for (let i = 0; i < tile.pointCount; i++) { - // POSITION_QUANTIZED * QUANTIZED_VOLUME_SCALE / 65535.0 + QUANTIZED_VOLUME_OFFSET + // POSITION = POSITION_QUANTIZED / 65535.0 * QUANTIZED_VOLUME_SCALE + QUANTIZED_VOLUME_OFFSET scratchPosition .set(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]) - // TODO - Remove this when deck.gl allows `normalized` flag to be set on `positions` .scale(1 / tile.quantizedRange) .multiply(tile.quantizedVolumeScale) - .add(tile.quantizedVolumeOffset); - - scratchPosition.toArray(decodedArray, i * 3); + .add(tile.quantizedVolumeOffset) + .toArray(decodedArray, i * 3); } return decodedArray;