The Reality Tiler tiles photogrammetry and reality models into optimized 3D Tiles 1.1 tilesets for runtime streaming and visualization.
Quickstart guide
Prerequisites
Linux
-
An OS that supports glibc 2.28 such as:
-
AlmaLinux 8.8 or later
-
Ubuntu 18.10 or later
-
Windows
-
Minimum OS: Windows 10 or Windows Server 2019
-
Visual C++ Redistributable for Visual Studio 2022. Download and run the installer.
Installing the license
A license is required to run tilers
. The license
file is provided separately from this packaged build.
Copy the license to the same directory as the tilers
executable. By default, the executable is located at bin/tilers
, so the license must be saved as bin/license
.
Usage
Print help
./bin/tilers --help
Run the Reality Tiler
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json
Viewing tilesets
To view the output tilesets, a rendering engine that supports 3D Tiles 1.1 such as one of the following is required.
-
CesiumJS 1.108.1 or later
-
Cesium for Unreal 1.25.0 or later
-
Cesium for Unity 1.1.0 or later
-
Cesium for Omniverse 0.7.0 or later
Viewing tilesets in CesiumJS
Tilesets produced by tilers
can be viewed in CesiumJS with the help of a static server.
Setting up a static server for local development
For local development, there are plenty of static servers available. The example
below will use the third-party npm
module http-server
, but any static
server can be substituted.
To install http-server
npm install -g http-server
cd directory/with/tilesets/
http-server --port 8002 --cors
Note that:
-
http-server
is intended for local development only, not production -
The port number can be changed if desired.
-
Since
https://sandcastle.cesium.com
andhttp://localhost:8002
are different origins, the static server must enable Cross-Origin Resource Sharing (CORS), hence the--cors
flag -
In the future, browsers may restrict access to localhost for security reasons, in similar manner to the CORS policy. See this
http-server
issue for more information.
Loading the tileset in CesiumJS
Once you have a server running, use Sandcastle to load and view the tileset.
const viewer = new Cesium.Viewer("cesiumContainer");
async function createTileset() {
// This tileset was not georeferenced, so we must provide a model matrix at runtime.
// Place the tileset at (longitude, latitude) = (0, 0) at 10 meters above the ellipsoid.
const tilesetPosition = Cesium.Cartesian3.fromRadians(0, 0, 10);
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(tilesetPosition);
// Create the tileset primitive
const tileset = await Cesium.Cesium3DTileset.fromUrl(
"http://localhost:8002/output/tileset.json",
{modelMatrix}
);
// Add it to the scene
viewer.scene.primitives.add(tileset);
// Zoom the camera to the tileset.
await viewer.zoomTo(tileset);
}
createTileset().catch(console.error);
You can similarly load the tileset into Unreal Engine, Unity, or Omniverse by copying the URL into the Cesium 3D Tileset object. For more information, you can follow this tutorial.
Reality Tiler
The Reality Tiler takes a large, textured 3D mesh and generates a 3D Tiles 1.1 tileset from it. This provides the following benefits:
-
The output tileset is a hierarchical level-of-detail (HLOD) representation of the mesh.
-
The HLOD structure enables optimized streaming and rendering across different types of devices and engines.
-
Geometry, texture and file compression can be applied to the tiles to reduce file size on disk and reduce network usage.
Command line example
./bin/tilers -i path/to/model.obj -o output/tileset.json
Frequently used options
Georeferencing tilesets
Georeference a tileset manually
# Position the model over downtown Chicago.
# longitude and latitude are in degrees.
# height is in meters above the WGS84 ellipsoid
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --longitude -87.6298 --latitude 41.8781 --height 100
There are options for setting the position, orientation and scale of the output:
Option | Description |
---|---|
|
The longitude in EPSG:4979 coordinates (degrees) to set an origin for the data. |
|
The latitude in EPSG:4979 coordinates (degrees) to set an origin for the data. |
|
The ellipsoid height in EPSG:4979 coordinates (meters) to set an origin for the data. |
|
The rotation in degrees from the local north direction where a positive angle is increasing eastward. |
|
The rotation in degrees from the local east-north plane. Positive pitch angles are above the plane. Negative pitch angles are below the plane. |
|
The rotation in degrees applied to the local east axis. |
|
The amount to scale in the x direction. |
|
The amount to scale in the y direction. |
|
The amount to scale in the z direction. |
Georeference a tileset with a coordinate reference system (CRS)
Often real-world data is measured with respect to a coordinate reference system. This includes map projections, geodetic coordinates (i.e. longitude, latitude, height), and other methods of assigning 3D coordinates to points on the earth’s surface. tilers
uses the PROJ library to parse data from these coordinate reference systems.
# Position the model above Center City Philadelphia, using the
# Pennsylvania State Plane South coordinate system (EPSG:2272)
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --input-crs EPSG:2272 --input-crs-origin-x 2693526.706772 --input-crs-origin-y 236133.329462 --input-crs-origin-z 100
In the above example, the --input-crs
specifies the CRS to use. The --input-crs-origin-(x|y|z)
options set an
origin point.
The CRS string must be a format supported by the PROJ library. Common examples include:
-
EPSG Codes. The European Petroleum Survey Group (EPSG) maintains a database of coordinate reference systems and other geodetic parameters, each with a unique identifier (the EPSG code). This is often the easiest option for widely-used coordinate reference systems.
-
The Open Geospatial Consortium (OGC) Well-Known Text (WKT) format. While more verbose, WKT strings are more expressive in describing the coordinate reference system.
-
PROJ strings. This is PROJ’s older, but still widely used, format for specifying a CRS.
For more information on what CRS strings that PROJ supports, see the proj_create() documentation
Georeferencing ContextCapture input
ContextCapture models often include georeferencing information in a sidecar XML file. The Reality Tiler does not currently parse such files, but the georeferencing information can be specified with command line flags.
For example, suppose the input file contained the following georeferencing information:
<?xml version="1.0" encoding="utf-8"?>
<ModelMetadata version="1">
<!--Spatial Reference System-->
<SRS>EPSG:28355+5773</SRS>
<!--Origin in Spatial Reference System-->
<SRSOrigin>319000,5813000,0</SRSOrigin>
<!-- ... -->
</ModelMetadata>
The <SRS>
tag ("Spatial Reference system") corresponds to the --input-crs
flag. The SRSOrigin
corresponds to the --input-crs-origin-(x|y|z)
flags.
For the example above, the corresponding tilers
command would look like this:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --input-crs EPSG:28355+5773 --input-crs-origin-x 319000 --input-crs-origin-y 5813000 --input-crs-origin-z 0
Note
|
A future release of the 3D Tiling Pipeline will automatically read sidecar files that provide CRS information. |
Compression
The 3D Tiling Pipeline offers a variety of compression options for the output. All files can be compressed using gzip compression. Furthermore, geometry and texture compression can be applied for glTF models in the output.
File compression: gzip
All files in the output tileset can be compressed with general-purpose gzip
compression using the --gzip flag
:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --gzip
Geometric compression: Draco
Note
|
This option is enabled by default in tilers
|
The Google Draco Library provides compression designed for 3D models. It can be used to compress glTF attributes using the KHR_draco_mesh_compression
glTF extension.
Draco is optimized for small file size. It may reorder vertices to achieve better compression.
Draco compresion includes quantizing the positions to a grid. This is a lossy compression technique that trades precision for fewer bits.
To use Draco compression, set the --geometric-compression DRACO
command line
flag.
Example:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --geometric-compression DRACO
By default, models are quantized to 1 millimeter precision. To control the quantization precision, use the --compression-precision-meters
flag. For example, to change the quantization to 1 centimeter precision, the command would be:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --geometric-compression DRACO --compression-precision-meters 0.01
Geometric compression: Meshopt
Meshopt is a different compression algorithm for 3D models that is optimized
for runtime performance. glTF attributes can be compressed using the EXT_meshopt_compression
extension. This extension is combined with KHR_mesh_quantization
(see the Quantization) for more efficient (lossy) compression.
To enable both meshopt and quantization, set --geometric-compression MESHOPT
.
Example:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --geometric-compression MESHOPT
By default, models are quantized to 1 millimeter precision. To control the quantization amount, use the`--compression-precision-meters` flag. For example, to change the quantization to 1 centimeter precision, the command would be:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --geometric-compression MESHOPT --compression-precision-meters 0.01
Geometric compression: quantization
For applying vertex quantization without compression, the Reality Tiler supports the KHR_mesh_quantization
as a standalone extension. This quantizes positions
to a grid specified by --compression-precision-meters
, which are then decoded
at runtime on the GPU. Quantized positions are stored as integers rather than
floats, which saves storage space.
To enable quantization, set --geometric-compression QUANTIZATION
as in the following example:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --geometric-compression QUANTIZATION --compression-precision-meters 0.01
Color texture compression: KTX2
Note
|
This option is enabled by default in tilers
|
For textures containing color information, the tiler supports the Khronos Texture (KTX) compressed textures. KTX v2.0 is an image container format that supports Basis Universal supercompression. These textures are optimized for rapid transcoding to GPU texture formats, which vary by device and manufacturer. This texture compression is applied to glTF models using the KHR_texture_basisu
glTF extension.
# Texture compression with KTX2.
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --color-texture-compression KTX2
When --color-texture-compression
is set to KTX2
, tilers
uses the
ETC1S
mode of BasisU for compressing textures. This format uses a lossy compression method that produces smaller textures than JPEG. It also has a small footprint at runtime, as it transcodes to GPU compressed texture formats.
Texture compression: JPEG
The tiler supports JPEG images for textures via the --color-texture-compression JPEG
option. JPEG images are smaller than PNG, and are more widely supported than KTX2. However, JPEG images use lossy compression.
Example:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --color-texture-compression JPEG
Texture compression: PNG
The tiler supports PNG textures for textures via the --color-texture-compression PNG
option. PNG images use lossless compression. This preserves detail of textures without any artifacts at the cost of larger file size.
Example:
./bin/tilers -i example/data/duck/duck.obj -o output/duck/tileset.json --color-texture-compression PNG
Out-of-core processing
The 3D Tiling Pipeline uses disk space for out of core (OOC) processing of large datasets that do not fit in physical memory.
-
A solid-state NVMe is recommended for best performance.
-
Make sure the disk where
tilers
is run has enough free space. 5-10x the size of the input data is recommended. -
If you interrupt
tilers
while running, please clean up temporary files with the nametilers_*.mmap
. By default, these files are stored in the system temporary files directory, which are typically:-
Linux:
/tmp
-
Windows:
C:\Users\<username>\AppData\Local\Temp
-
Frequently asked questions
Tileset is rotated 90 degrees
If the output tileset appears rotated 90 degrees from the correct orientation,
check which axis is up for the original dataset, and set --input-up-axis
accordingly. By default, the 3D Tiling Pipeline assumes a y-up
coordinate system for glTF models and z-up coordinate system for OBJ models.
The --input-up-axis
setting is mutually exclusive with the --input-crs
option, as the latter assumes the data uses the coordinate system of the CRS
Tileset appears at the center of the earth
If the tileset appears at the center of the earth, the data is likely in a local coordinate system and needs an additional matrix transform at runtime to position and orient the tileset on the globe.
This can be done two different ways:
-
Use the 3D Tiling Pipeline’s georeferencing options to position the tileset.
-
At runtime, apply a model matrix to the tileset to position it on the globe. See the Viewing tilesets in CesiumJS section for more details.
Tileset appears in the wrong location on earth
If the tileset appears in space or somewhere else unexpected on the globe,
the input data may require georeferencing. The CLI option --input-crs
can be used to specify the coordinate reference system
(CRS) as an EPSG code, a PROJ string, or a WKT string.
Technical reference
Input model requirements
The Reality Tiler accepts textured 3D models in glTF or OBJ format. There are further requirements, listed below.
glTF input requirements
a glTF input must meet the following requirements:
-
Primitives
-
glTF input models must have at least one mesh primitive
-
primitives must use the
TRIANGLES
mode
-
-
Attributes
-
Models must have a
POSITION
attribute -
Textured models must also have a
TEXCOORD_0
attribute -
All other attributes are currently ignored (including vertex colors)
-
No glTF extensions for attributes (e.g. for compression) are currently supported.
-
All mesh primitives (across all input glTF assets combined) must have the same number of attributes.
-
-
Materials
-
Currently only
baseColorTexture
andbaseColorFactor
are supported. -
baseColorTexture
must useTEXCOORD_0
-
the
KHR_materials_unlit
extension will be propagated to the output.
-
-
Textures
-
Only PNG and JPEG formats are supported
-
No texture extensions are currently supported
-
If a model has no texture, or references a texture that is not found when a model is loaded, the Reality Tiler will use a 1x1 px white texture instead.
-
All texture wrap modes (
wrapS
/wrapT
) are supported. However, repeated textures may require large amounts of virtual memory. For best results, use models with all texture coordinates within the range[0, 1]
.
-
-
Accessors/Buffer Views
-
glTF assets that have shared accessors and/or buffer views are supported. However, this is expanded when tiling which may require large amounts of virtual memory.
-
OBJ input requirements
-
.obj
and.mtl
files must use UTF-8 encoding. -
Models must have vertices (
v
) -
The input models may have n-gon faces, they will be triangulated in the output
-
Textured Models must have texture coordinates (
vt
) -
Only the diffuse color texture (
map_Kd
) or diffuse factor (Kd
) are supported -
Only PNG and JPEG textures are currently supported.
-
All other vertex attributes (normals, vertex colors) are ignored.
-
out-of-bounds texcoords are assumed
REPEAT
texture wrapping. the-clamp
flag is not supported. -
If the OBJ references a file with spaces in the filename, the filename must be enclosed in quotes, e.g.
"my mesh.obj"
or the space must be escaped with a backslash, e.g.my\ mesh.obj
.
3D Tiles 1.1 output
The Reality Tiler produces a 3D Tiles 1.1 tileset. It uses the following features of the specification:
-
-
Each tile contains a single content in glTF format.
-
Each glTF asset consists of a single triangle mesh with a base color texture
-
The mesh’s material uses the
KHR_materials_unlit
extension, as reality models often look best without shading -
Mesh primitives contain
POSITION
andTEXCOORD_0
attributes. -
Future releases of the 3D Tiling Pipeline will preserve more attributes and metadata from the input model
-
-
-
The tileset is an octree and uses implicit tiling for efficient run-time queries by Morton index. Furthermore, only the root bounding volume needs to be stored, which keeps the
tileset.json
small.
-
-
-
TILE_BOUNDING_BOX
- The root tile contains a metadata property with this semantic to store a tighter bounding box than the one used for implicit tiling. Runtime engines can use this bounding box to produce a better camera view when zooming to the tileset. See for example this CesiumJS PR.
-
Error codes list
Below is a list of all error codes supported in the 3D Tiling Pipeline. Each error consists of three parts: a unique numerical code, a "category", and a string description. There are three error categories:
-
USER
- an issue with input data or incompatible CLI arguments -
CONFIG
- an issue with the provided config file, e.g. invalid options -
INTERNAL
- an internal processing error
Error | Code | Category | Description |
---|---|---|---|
INPUT_INVALID |
0 |
USER |
An input to the tiler (such as a command line flag) is invalid |
INPUT_FILE_MISSING |
1 |
USER |
One of the specified input files could not be found |
INPUT_FILE_INVALID |
2 |
USER |
One of the specified input files is invalid |
INPUT_UNSUPPORTED |
3 |
USER |
One of the specified input files has unsupported feature. |
INPUT_FILE_TOO_BIG |
4 |
USER |
The input file does not fit in availabile virtual memory. |
PARAMETER_INVALID |
5000 |
CONFIG |
A config file parameter is invalid |
PARAMETER_OUT_OF_RANGE |
5001 |
CONFIG |
A config file parameter is out of the allowed range |
PARAMETER_NOT_ALLOWED |
5002 |
CONFIG |
A config file parameter is not a valid value |
Additionally, many error types contain a reason
field to provide more details.
The list of reason codes is as follows:
Error reason | Description |
---|---|
CONFIG_PARSE_FAILURE |
Failed to parse the config JSON file. |
CLI_NO_INPUT_PROVIDED |
No config file, input or input list was provided. |
CLI_MISSING_REQUIRED_OPTIONS |
A required command line option was omitted. |
CLI_OPTION_INVALID_ARGUMENT_TYPE |
A provided command-line option has an argument that does not have the expected type and could not be parsed. |
CLI_OPTION_REQUIRES_ARGUMENT |
A provided command-line option does not have an argument but requires one. |
CLI_OPTION_REQUIRES_NO_ARGUMENT |
A provided command-line option has an argument but does not take one. |
CLI_OPTION_INVALID |
A provided command-line option is not recognized. |
CLI_PARSE_FAILURE |
There was an error parsing the CLI options. |
CRS_TYPE_MISMATCH |
The specified coordinate reference systems are incompatible. This can happen if one CRS is a local coordinate system and another is a global coordinate system. |
DIRECTORY_REMOVAL_FAILURE |
Could not remove the specified directory. |
EXECUTABLE_INSIDE_OUTPUT |
The tilers executable was inside the output directory and would be overwritten. |
FILE_READ_FAILURE |
The specified file could not be read. |
FILE_REMOVAL_FAILURE |
The specified file could not be deleted. |
FILE_WRITE_FAILURE |
The specified file could not be written. |
FILE_EMPTY |
The specified file is empty. |
GEOREFERENCE_SCALE_ZERO |
The scale factor provided with |
GLTF_BUFFER_DATA_URI_INVALID |
A data URI for a glTF buffer is invalid. |
GLTF_DESERIALIZE_FAILURE |
The glTF model failed to load. |
GLTF_DESERIALIZE_WARNING |
A warning was emitted when the glTF model was loaded. |
GLTF_LOAD_IMAGE_URI_INVALID |
The specified URI in the glTF is invalid, but should point to an image. |
GLTF_LOAD_BUFFER_URI_INVALID |
The specified URI in the glTF is invalid, but should point to a glTF buffer. |
GLTF_NO_MESHES |
The input glTF file does not have any meshes. |
GLTF_NO_POSITIONS |
The input glTF file does not have any primitive with a POSITION attribute. |
GLTF_NO_PRIMITIVES |
The input glTF file does not have any primitive. |
INPUT_CRS_ORIGIN_MISSING_CRS |
|
INPUT_FORMAT_MISMATCH |
The input contains a mix of different input file formats. Tilers currently requires all inputs to have the same format. |
INPUT_FORMAT_UNKNOWN |
The input format could not be determined from the input file. |
INPUT_INSIDE_OUTPUT |
The input directory is inside the output directory and would be overwritten. |
PATH_INVALID |
The specified path is not a valid file path. |
INPUT_SAME_AS_OUTPUT |
The input directory is the same as the output directory and would be overwritten. |
INPUT_LIST_READ_FAILURE |
The file with input paths could not be read. |
INPUT_AND_INPUT_LIST_MUTUALLY_EXCLUSIVE |
|
INVALID_CRS |
The coordinate reference system was not valid. It must be a CRS supported by the PROJ library. |
INVALID_PIPELINE |
The input provided is incompatible with the selected pipeline. |
LICENSE_INVALID |
The provided license was invalid. |
MODEL_FORMAT_UNSUPPORTED |
The input model uses a format not supported by the 3D Tiling Pipeline. |
MODEL_DECODE_IMAGE_FAILURE |
An image from a model could not be decoded. |
NO_INPUT_MODELS |
No valid input models could be read from the input. |
NO_INPUT_PROVIDED |
No input path(s) were specified. |
NO_OUTPUT_PROVIDED |
No output path was specififed. |
NO_PIPELINE |
The pipeline to use could not be determined from the input and output formats. |
NO_VALID_INPUT_FILE |
None of the input file(s) contain valid meshes for tiling. |
OBJ_DECODE_IMAGE_FAILURE (Unused) |
An image from an OBJ file could not be decoded. |
OBJ_NO_VALID_DATA |
The input OBJ file does not contain any valid data. |
OBJ_LOAD_ERROR |
The specified OBJ file failed to load. |
OBJ_LOAD_WARNING |
A warning was emitted when loading the OBJ file. |
OBJ_INVALID_TEXCOORD_INDEX |
The OBJ contains one or more invalid texture coordinate index. |
OBJ_INVALID_NORMAL_INDEX |
The OBJ contains one or more invalid normal index. |
OBJ_INVALID_POSITION_INDEX |
The OBJ contains one or more invalid vertex position index. |
OUTPUT_ALREADY_EXISTS |
The output directory already exists and would be overwritten. To force writing to this directory, use the |
TEMP_DIRECTORY_NOT_FOUND |
The temporary directory could not be found. |
TEMP_DIRECTORY_CREATE_FAILURE |
The tiler could not create the temporary directory. |
VERTEX_COLORS_UNSUPPORTED |
Vertex colors are not yet supported. |
GLTF_EXTENSION_UNSUPPORTED |
glTF extension not currently supported. |
MODEL_TOO_BIG |
Input model is too big, not enough virtual memory to load it. |
GLTF_EXCESSIVE_SHARED_BUFFERVIEWS |
glTF bufferViews sharing can currently require an excessive amount of virtual memory. If this is a CAD model, try the CAD tiler instead. |
MODEL_EXCESSIVE_TEXTURE_REPEAT |
Model has triangles that span many copies of the texture. This would require excessive virtual memory to texture bake in terms of virtual memory. If this is a CAD model, try the CAD tiler instead. |
GLTF_BUFFER_VIEW_OUT_OF_BOUNDS |
A glTF buffer view extends past the end of the underlying buffer. |
GLTF_ACCESSOR_OUT_OF_BOUNDS |
The glTF accessor extends past the end of the underlying buffer view. |
GLTF_MISSING_ACCESSOR |
The glTF references an accessor that does not exist. |
GLTF_MISSING_BUFFER_VIEW |
The glTF references a buffer view that does not exist. |
GLTF_MISSING_BUFFER |
The glTF references a buffer that does not exist. |
GLTF_MISSING_IMAGE |
The glTF references an image that does not exist. |
GLTF_PRIMITIVE_MODE_UNSUPPORTED |
glTF primitive modes other than TRIANGLES (mode = 4) are not supported. |