123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- import Cartesian3 from "../Core/Cartesian3.js";
- import Check from "../Core/Check.js";
- import Color from "../Core/Color.js";
- import combine from "../Core/combine.js";
- import ComponentDatatype from "../Core/ComponentDatatype.js";
- import defaultValue from "../Core/defaultValue.js";
- import defined from "../Core/defined.js";
- import getJsonFromTypedArray from "../Core/getJsonFromTypedArray.js";
- import RuntimeError from "../Core/RuntimeError.js";
- import AttributeType from "./AttributeType.js";
- import Cesium3DTileFeatureTable from "./Cesium3DTileFeatureTable.js";
- import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
- /**
- * Handles parsing of a Point Cloud
- *
- * @namespace PntsParser
- * @private
- */
- const PntsParser = {};
- const sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
- /**
- * Parses the contents of a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/PointCloud|Point Cloud}.
- *
- * @private
- *
- * @param {*} arrayBuffer The array buffer containing the pnts
- * @param {*} [byteOffset=0] The byte offset of the beginning of the pnts in the array buffer
- * @returns {object} An object containing a parsed representation of the point cloud
- */
- PntsParser.parse = function (arrayBuffer, byteOffset) {
- byteOffset = defaultValue(byteOffset, 0);
- //>>includeStart('debug', pragmas.debug);
- Check.defined("arrayBuffer", arrayBuffer);
- //>>includeEnd('debug');
- const uint8Array = new Uint8Array(arrayBuffer);
- const view = new DataView(arrayBuffer);
- byteOffset += sizeOfUint32; // Skip magic
- const version = view.getUint32(byteOffset, true);
- if (version !== 1) {
- throw new RuntimeError(
- `Only Point Cloud tile version 1 is supported. Version ${version} is not.`
- );
- }
- byteOffset += sizeOfUint32;
- // Skip byteLength
- byteOffset += sizeOfUint32;
- const featureTableJsonByteLength = view.getUint32(byteOffset, true);
- if (featureTableJsonByteLength === 0) {
- throw new RuntimeError(
- "Feature table must have a byte length greater than zero"
- );
- }
- byteOffset += sizeOfUint32;
- const featureTableBinaryByteLength = view.getUint32(byteOffset, true);
- byteOffset += sizeOfUint32;
- const batchTableJsonByteLength = view.getUint32(byteOffset, true);
- byteOffset += sizeOfUint32;
- const batchTableBinaryByteLength = view.getUint32(byteOffset, true);
- byteOffset += sizeOfUint32;
- const featureTableJson = getJsonFromTypedArray(
- uint8Array,
- byteOffset,
- featureTableJsonByteLength
- );
- byteOffset += featureTableJsonByteLength;
- const featureTableBinary = new Uint8Array(
- arrayBuffer,
- byteOffset,
- featureTableBinaryByteLength
- );
- byteOffset += featureTableBinaryByteLength;
- // Get the batch table JSON and binary
- let batchTableJson;
- let batchTableBinary;
- if (batchTableJsonByteLength > 0) {
- // Has a batch table JSON
- batchTableJson = getJsonFromTypedArray(
- uint8Array,
- byteOffset,
- batchTableJsonByteLength
- );
- byteOffset += batchTableJsonByteLength;
- if (batchTableBinaryByteLength > 0) {
- // Has a batch table binary
- batchTableBinary = new Uint8Array(
- arrayBuffer,
- byteOffset,
- batchTableBinaryByteLength
- );
- byteOffset += batchTableBinaryByteLength;
- }
- }
- const featureTable = new Cesium3DTileFeatureTable(
- featureTableJson,
- featureTableBinary
- );
- const pointsLength = featureTable.getGlobalProperty("POINTS_LENGTH");
- featureTable.featuresLength = pointsLength;
- if (!defined(pointsLength)) {
- throw new RuntimeError(
- "Feature table global property: POINTS_LENGTH must be defined"
- );
- }
- let rtcCenter = featureTable.getGlobalProperty(
- "RTC_CENTER",
- ComponentDatatype.FLOAT,
- 3
- );
- if (defined(rtcCenter)) {
- rtcCenter = Cartesian3.unpack(rtcCenter);
- }
- // Start with the draco compressed properties and add in uncompressed
- // properties.
- const parsedContent = parseDracoProperties(featureTable, batchTableJson);
- parsedContent.rtcCenter = rtcCenter;
- parsedContent.pointsLength = pointsLength;
- if (!parsedContent.hasPositions) {
- const positions = parsePositions(featureTable);
- parsedContent.positions = positions;
- parsedContent.hasPositions =
- parsedContent.hasPositions || defined(positions);
- }
- if (!parsedContent.hasPositions) {
- throw new RuntimeError(
- "Either POSITION or POSITION_QUANTIZED must be defined."
- );
- }
- if (!parsedContent.hasNormals) {
- const normals = parseNormals(featureTable);
- parsedContent.normals = normals;
- parsedContent.hasNormals = parsedContent.hasNormals || defined(normals);
- }
- if (!parsedContent.hasColors) {
- const colors = parseColors(featureTable);
- parsedContent.colors = colors;
- parsedContent.hasColors = parsedContent.hasColors || defined(colors);
- parsedContent.hasConstantColor = defined(parsedContent.constantColor);
- parsedContent.isTranslucent = defined(colors) && colors.isTranslucent;
- }
- if (!parsedContent.hasBatchIds) {
- const batchIds = parseBatchIds(featureTable);
- parsedContent.batchIds = batchIds;
- parsedContent.hasBatchIds = parsedContent.hasBatchIds || defined(batchIds);
- }
- if (parsedContent.hasBatchIds) {
- const batchLength = featureTable.getGlobalProperty("BATCH_LENGTH");
- if (!defined(batchLength)) {
- throw new RuntimeError(
- "Global property: BATCH_LENGTH must be defined when BATCH_ID is defined."
- );
- }
- parsedContent.batchLength = batchLength;
- }
- if (defined(batchTableBinary)) {
- // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed
- batchTableBinary = new Uint8Array(batchTableBinary);
- parsedContent.batchTableJson = batchTableJson;
- parsedContent.batchTableBinary = batchTableBinary;
- }
- return parsedContent;
- };
- function parseDracoProperties(featureTable, batchTableJson) {
- const featureTableJson = featureTable.json;
- let dracoBuffer;
- let dracoFeatureTableProperties;
- let dracoBatchTableProperties;
- const featureTableDraco = defined(featureTableJson.extensions)
- ? featureTableJson.extensions["3DTILES_draco_point_compression"]
- : undefined;
- const batchTableDraco =
- defined(batchTableJson) && defined(batchTableJson.extensions)
- ? batchTableJson.extensions["3DTILES_draco_point_compression"]
- : undefined;
- if (defined(batchTableDraco)) {
- dracoBatchTableProperties = batchTableDraco.properties;
- }
- let hasPositions;
- let hasColors;
- let hasNormals;
- let hasBatchIds;
- let isTranslucent;
- if (defined(featureTableDraco)) {
- dracoFeatureTableProperties = featureTableDraco.properties;
- const dracoByteOffset = featureTableDraco.byteOffset;
- const dracoByteLength = featureTableDraco.byteLength;
- if (
- !defined(dracoFeatureTableProperties) ||
- !defined(dracoByteOffset) ||
- !defined(dracoByteLength)
- ) {
- throw new RuntimeError(
- "Draco properties, byteOffset, and byteLength must be defined"
- );
- }
- dracoBuffer = featureTable.buffer.slice(
- dracoByteOffset,
- dracoByteOffset + dracoByteLength
- );
- hasPositions = defined(dracoFeatureTableProperties.POSITION);
- hasColors =
- defined(dracoFeatureTableProperties.RGB) ||
- defined(dracoFeatureTableProperties.RGBA);
- hasNormals = defined(dracoFeatureTableProperties.NORMAL);
- hasBatchIds = defined(dracoFeatureTableProperties.BATCH_ID);
- isTranslucent = defined(dracoFeatureTableProperties.RGBA);
- }
- let draco;
- if (defined(dracoBuffer)) {
- draco = {
- buffer: dracoBuffer,
- featureTableProperties: dracoFeatureTableProperties,
- batchTableProperties: dracoBatchTableProperties,
- properties: combine(
- dracoFeatureTableProperties,
- dracoBatchTableProperties
- ),
- dequantizeInShader: true,
- };
- }
- return {
- draco: draco,
- hasPositions: hasPositions,
- hasColors: hasColors,
- isTranslucent: isTranslucent,
- hasNormals: hasNormals,
- hasBatchIds: hasBatchIds,
- };
- }
- function parsePositions(featureTable) {
- const featureTableJson = featureTable.json;
- let positions;
- if (defined(featureTableJson.POSITION)) {
- positions = featureTable.getPropertyArray(
- "POSITION",
- ComponentDatatype.FLOAT,
- 3
- );
- return {
- name: VertexAttributeSemantic.POSITION,
- semantic: VertexAttributeSemantic.POSITION,
- typedArray: positions,
- isQuantized: false,
- componentDatatype: ComponentDatatype.FLOAT,
- type: AttributeType.VEC3,
- };
- } else if (defined(featureTableJson.POSITION_QUANTIZED)) {
- positions = featureTable.getPropertyArray(
- "POSITION_QUANTIZED",
- ComponentDatatype.UNSIGNED_SHORT,
- 3
- );
- const quantizedVolumeScale = featureTable.getGlobalProperty(
- "QUANTIZED_VOLUME_SCALE",
- ComponentDatatype.FLOAT,
- 3
- );
- if (!defined(quantizedVolumeScale)) {
- throw new RuntimeError(
- "Global property: QUANTIZED_VOLUME_SCALE must be defined for quantized positions."
- );
- }
- const quantizedRange = (1 << 16) - 1;
- const quantizedVolumeOffset = featureTable.getGlobalProperty(
- "QUANTIZED_VOLUME_OFFSET",
- ComponentDatatype.FLOAT,
- 3
- );
- if (!defined(quantizedVolumeOffset)) {
- throw new RuntimeError(
- "Global property: QUANTIZED_VOLUME_OFFSET must be defined for quantized positions."
- );
- }
- return {
- name: VertexAttributeSemantic.POSITION,
- semantic: VertexAttributeSemantic.POSITION,
- typedArray: positions,
- isQuantized: true,
- componentDatatype: ComponentDatatype.FLOAT,
- type: AttributeType.VEC3,
- quantizedRange: quantizedRange,
- quantizedVolumeOffset: Cartesian3.unpack(quantizedVolumeOffset),
- quantizedVolumeScale: Cartesian3.unpack(quantizedVolumeScale),
- quantizedComponentDatatype: ComponentDatatype.UNSIGNED_SHORT,
- quantizedType: AttributeType.VEC3,
- };
- }
- }
- function parseColors(featureTable) {
- const featureTableJson = featureTable.json;
- let colors;
- if (defined(featureTableJson.RGBA)) {
- colors = featureTable.getPropertyArray(
- "RGBA",
- ComponentDatatype.UNSIGNED_BYTE,
- 4
- );
- return {
- name: VertexAttributeSemantic.COLOR,
- semantic: VertexAttributeSemantic.COLOR,
- setIndex: 0,
- typedArray: colors,
- componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
- type: AttributeType.VEC4,
- normalized: true,
- isRGB565: false,
- isTranslucent: true,
- };
- } else if (defined(featureTableJson.RGB)) {
- colors = featureTable.getPropertyArray(
- "RGB",
- ComponentDatatype.UNSIGNED_BYTE,
- 3
- );
- return {
- name: "COLOR",
- semantic: VertexAttributeSemantic.COLOR,
- setIndex: 0,
- typedArray: colors,
- componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
- type: AttributeType.VEC3,
- normalized: true,
- isRGB565: false,
- isTranslucent: false,
- };
- } else if (defined(featureTableJson.RGB565)) {
- colors = featureTable.getPropertyArray(
- "RGB565",
- ComponentDatatype.UNSIGNED_SHORT,
- 1
- );
- return {
- name: "COLOR",
- semantic: VertexAttributeSemantic.COLOR,
- setIndex: 0,
- typedArray: colors,
- // These settings are for the Model implementation
- // which decodes on the CPU and uploads a VEC3 of float colors.
- // PointCloud does the decoding on the GPU so uploads a
- // UNSIGNED_SHORT instead.
- componentDatatype: ComponentDatatype.FLOAT,
- type: AttributeType.VEC3,
- normalized: false,
- isRGB565: true,
- isTranslucent: false,
- };
- } else if (defined(featureTableJson.CONSTANT_RGBA)) {
- const constantRGBA = featureTable.getGlobalProperty(
- "CONSTANT_RGBA",
- ComponentDatatype.UNSIGNED_BYTE,
- 4
- );
- const alpha = constantRGBA[3];
- const constantColor = Color.fromBytes(
- constantRGBA[0],
- constantRGBA[1],
- constantRGBA[2],
- alpha
- );
- const isTranslucent = alpha < 255;
- return {
- name: VertexAttributeSemantic.COLOR,
- semantic: VertexAttributeSemantic.COLOR,
- setIndex: 0,
- constantColor: constantColor,
- componentDatatype: ComponentDatatype.FLOAT,
- type: AttributeType.VEC4,
- isQuantized: false,
- isTranslucent: isTranslucent,
- };
- }
- return undefined;
- }
- function parseNormals(featureTable) {
- const featureTableJson = featureTable.json;
- let normals;
- if (defined(featureTableJson.NORMAL)) {
- normals = featureTable.getPropertyArray(
- "NORMAL",
- ComponentDatatype.FLOAT,
- 3
- );
- return {
- name: VertexAttributeSemantic.NORMAL,
- semantic: VertexAttributeSemantic.NORMAL,
- typedArray: normals,
- octEncoded: false,
- octEncodedZXY: false,
- componentDatatype: ComponentDatatype.FLOAT,
- type: AttributeType.VEC3,
- };
- } else if (defined(featureTableJson.NORMAL_OCT16P)) {
- normals = featureTable.getPropertyArray(
- "NORMAL_OCT16P",
- ComponentDatatype.UNSIGNED_BYTE,
- 2
- );
- const quantizationBits = 8;
- return {
- name: VertexAttributeSemantic.NORMAL,
- semantic: VertexAttributeSemantic.NORMAL,
- typedArray: normals,
- octEncoded: true,
- octEncodedZXY: false,
- quantizedRange: (1 << quantizationBits) - 1,
- quantizedType: AttributeType.VEC2,
- quantizedComponentDatatype: ComponentDatatype.UNSIGNED_BYTE,
- componentDatatype: ComponentDatatype.FLOAT,
- type: AttributeType.VEC3,
- };
- }
- return undefined;
- }
- function parseBatchIds(featureTable) {
- const featureTableJson = featureTable.json;
- if (defined(featureTableJson.BATCH_ID)) {
- const batchIds = featureTable.getPropertyArray(
- "BATCH_ID",
- ComponentDatatype.UNSIGNED_SHORT,
- 1
- );
- return {
- name: VertexAttributeSemantic.FEATURE_ID,
- semantic: VertexAttributeSemantic.FEATURE_ID,
- setIndex: 0,
- typedArray: batchIds,
- componentDatatype: ComponentDatatype.fromTypedArray(batchIds),
- type: AttributeType.SCALAR,
- };
- }
- return undefined;
- }
- export default PntsParser;
|