Module @xeokit/compression - v0.1.0

npm version

xeokit SceneGeometry Compression / Decompression Utilities


Tools for geometry compression and decompression


The xeokit SceneGeometry Compression/Decompression Utilities library provides functions used internally within SceneModel.createGeometry implementations to compress geometry. These functions are also provided for users who want to pre-compress their geometry "offline" and then use SceneModel.createGeometryCompressed to create compressed geometry directly.

The compression techniques used include simplifying geometry by combining duplicate positions and adjusting indices, generating edge indices for triangle meshes, ignoring normals (as shaders auto-generate them), converting positions to relative-to-center (RTC) coordinates, quantizing positions and UVs as 16-bit unsigned integers, and splitting geometry into buckets to enable indices to use the minimum bits for storage. The bucketing technique was developed for xeokit by Toni Marti with support from Tribia AG.

An example usage includes compressing a SceneGeometryParams into a @xeokit/scene!SceneGeometryCompressedParams using the @xeokit/scene!compressGeometryParams function. In this example, the geometry is simple, and only one bucket is needed. However, if the positions array was large enough to require some indices to use more than 16 bits for storage, the bucketing mechanism would split the geometry into smaller buckets, each with smaller indices that index a subset of the positions.

The resulting SceneGeometryCompressedParams object shows that we have one bucket with vertex positions relative to the origin and quantized to 16-bit integers, duplicate positions removed, and adjusted indices. Additionally, edge indices are generated for the @xeokit/constants!TrianglesPrimitive, and a positionsDecompressMatrix is included to de-quantize the positions within the Viewer.

This library provides a set of functions that are used internally within SceneModel.createGeometry implementations to compress geometry. The functions are provided here in case users instead want to pre-compress their geometry "offline", and then use SceneModel.createGeometryCompressed to create the compressed geometry directly.

Compression Techniques Used

  • Simplifies geometry by combining duplicate positions and adjusting indices
  • Generates edge indices for triangle meshes
  • Ignores normals (our shaders auto-generate them)
  • Converts positions to relative-to-center (RTC) coordinates
  • Quantizes positions and UVs as 16-bit unsigned integers
  • Splits geometry into buckets to enable indices to use the minimum bits for storage

Aknowledgements

  • The bucketing technique mentioned above was developed for xeokit by Toni Marti, with support from Tribia AG. Read the slides from Toni's presentation at WebGL Meetup 2022.

Installation

npm install @xeokit/compression

Usage

In the example below, we'll use @xeokit/scene!compressGeometryParams to compress a SceneGeometryParams into a SceneGeometryCompressedParams.

In this example, our geometry is very simple, and our SceneGeometryCompressedParams only gets a single SceneGeometryBucketParams. Note that if the SceneGeometryParams.positions array was large enough to require some of the indices to use more than 16 bits for storage, then that's when the function's bucketing mechanism would kick in, to split the geometry into smaller buckets, each with smaller indices that index a subset of the positions.

import {compressGeometryParams} from "@xeokit/compression";
import {TrianglesPrimitive} from "@xeokit/constants";

const geometryCompressedParams = compressGeometryParams({
id: "myBoxGeometry",
primitive: TrianglesPrimitive,
positions: [
202, 202, 202, 200, 202, 202,
200, 200, 202, 202, 200, 202,
202, 202, 202, 202, 200, 202,
202, 200, 200, 202, 202, 200,
202, 202, 202, 202, 202, 200,
200, 202, 200, 200, 202, 202,
200, 202, 202, 200, 202, 200,
200, 200, 200, 200, 200, 202,
200, 200, 200, 202, 200, 200,
202, 200, 202, 200, 200, 202,
202, 200, 200, 200, 200, 200,
200, 202, 200, 202, 202, 200
],
indices: [
0, 1, 2, 0, 2, 3, 4, 5, 6, 4,
6, 7, 8, 9, 10, 8, 10, 11, 12,
13, 14, 12, 14, 15, 16, 17, 18,
16, 18, 19, 20, 21, 22, 20, 22, 23
]
});

The value of our new SceneGeometryCompressedParams is shown below.

We can see that:

  • We get one bucket, because we have only a small number of indices
  • Vertex positions are now relative to origin and quantized to 16-bit integers
  • Duplicate positions are removed and indices adjusted
  • Edge indices generated for our TrianglesPrimitive
  • A positionsDecompressMatrix to de-quantize the positions within the Viewer
{
id: "myBoxGeometry",
primitive: TrianglesPrimitive,
origin: [200,200,200],
positionsDecompressMatrix: [
0.00003052270125906143, 0, 0, 0,
0, 0.00003052270125906143, 0, 0,
0, 0, 0.00003052270125906143, 0,
-1, -1, -1, 1
],
geometryBuckets: [
{
positionsCompressed: [
65525, 65525, 65525, 0, 65525, 65525,
0, 0, 65525, 65525, 0, 65525, 65525,
0, 0, 65525, 65525, 0, 0, 65525, 0, 0,
0, 0
],
indices: [
0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6,
0, 6, 1, 1, 6, 7, 1, 7, 2, 7, 4, 3, 7, 3, 2,
4, 7, 6, 4, 6, 5
],
edgeIndices: [
3, 4, 0, 4, 5, 0, 5, 6,
0, 6, 1, 1, 6, 7, 1, 7,
3, 2, 4, 7, 6, 4, 6
]
}
]
}

In the next example, we'll again use @xeokit/scene!compressGeometryParams to compress a SceneGeometryParams into a SceneGeometryCompressedParams, which we'll then use to create a compressed geometry within a SceneModel.

import {Scene} from "@xeokit/scene";
import {TrianglesPrimitive} from "@xeokit/constants";
import {compressGeometryParams} from "@xeokit/compression";

const scene = new Scene();

const sceneModel = scene.createModel({
id: "myModel"
});

const geometryCompressedParams = compressGeometryParams({
id: "myBoxGeometry",
primitive: TrianglesPrimitive,
positions: [202, 202, 202, 200, 202, 202, ...],
indices: [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, ...]
});

sceneModel.createGeometryCompressed(geometryCompressedParams);

sceneModel.createLayerMesh({ id: "myMesh", geometryId: "myGeometry" });

sceneModel.createObject({ id: "myObject1", meshIds: ["myMesh"] });
sceneModel.createObject({ id: "myObject2", meshIds: ["myMesh"] });

sceneModel.build();

@xeokit/compression

Index

Functions

Generated using TypeDoc