Nexus: adaptive 3D (C++ and Javascript)

Nexus is a collection of tools for streaming visualization of large 3D models in OpenGL (C++ and Javascript).

Source code and windows releases can be found on Github

Main features:

  • Multiresolution: 3D models are converted in a data structure that allows view dependent resolution
  • Out of core: very large models with very large textures can be processed and visualized with limited resources
  • Compression: the Corto compression algorithm provides good compression and very fast decompression
  • Streaming: the 3D models are streamed over the network in an efficient way
  • WebGL: a library for WebGL visualization
  • Three.js: a loader that can be seamlessly integrated into Three.js
  • 3DHOP: a rendering engine for the 3DHOP open-source framework

Nexus supports point clouds and meshes with per vertex attributes: normals, colors, texture coordinates and stores textures internally.

The package is composed of:

  • Nxsbuild: generates a .nxs from a .ply or .obj
  • Nxsedit: compress, prune or export in .ply the model
  • Nxsview: a simple viewer for .nxs files
  • Nexus.js: a javascript library to load, decompress and send the geometry to the GPU
Monreale capital

Monreale 30MB 4.7MT
Courtesy of VCG


Sarcophagus 50MB 14MT
Courtesy of VCG

Small cave

Cave 36MB 10MT
Courtesy of VCG

Tarta toy

Clay toy 17MB 6.5MT
Courtesy of VCG


Portalada 100MB 180MT
Courtesy of VCG


Spouses 15MB 60MT
Courtesy of VCG

San Silvestro

S.Silvestro 28MB 9MV
Courtesy of VCG

Bonifacio VIII

Bonifacio 200MB 84MT
Courtesy of VCG


Source code and Windows executables are available at:

Test models for the Windows executables (zip archive ~56MB) are available here


Nxsbuild convert one (or more) .ply or an .obj into a multiresolution .nxs model; the process involves generating a sequence of increasingly coarse partitions of the mesh, interleaved with simplifications steps.

To compress the file see nxsedit

Usage: nxsbuild [ARGS] [-oftdsavqr]

ARGS can be one or more .ply and .obj

-o <val> --output_filename <val>     filename of the nexus output file
-f <val> --node_faces <val>          faces per patch, default: 16286
-t <val> --top_node_faces <val>      number of triangles in the top node,
                                     default 4096
-d <val> --decimation <val>          decimation method: quadric, edgelen.
                                     Default: quadric
-s <val> --scaling <val>             scaling between level, default 0.5
-O --orig_textures                   Use original textures, no repacking
-a <val> --adaptive <val>            split notes adaptively [0...1] default
-v <val> --vertex_quantization <val> approximated to closest power of 2
-q <val> --texture quality <val>     jpeg quality for texture [0-100] default
-p --point_cloud                     generate a multiresolution point cloud
-N --normals                         force per vertex normals even in point
-n --no_normals                      do not store per vertex normals
-C --colors                          save colors
-c --no_colors                       do not tore per vertex colors
-u --no_textures                     do not store per vertex texture
-r <val> --ram <val>                 max ram used (in Megabytes default 2000)
                                     WARNING: not a hard limit, increase at
                                     your risk :P

If a model is composed by several pieces nxsbuild can join them in a single .nxs

node_faces options controls the granularity of the multiresolution:

  • large values perform best in term of performances (fps), compression and minimized server requests, unless the model has very large textures for small number of vertices.
  • small values allow smoother change in resolution of the model, and better incremental update of textures and geometry sent to the GPU.

adaptive might need to be changed for models with really uneven triangle size


Nxsedit allow to modify a .nxs:

  • Compress: reduce size of the model to 10-20% (the extensio is .nxz
  • Prune: remove lower levels of the hierarchy
  • Export: output a .ply (a sort of out of core simplification).
  • Debug: info about the hierarhy
Usage: nxsedit <nexus file> [ARGS] [-opsetZvVYCANTQEmM]

nexus file                           path to the nexus file (add .nxs or not)
-i --info                            prints info about the nexus
-n --show_nodes                      prints info about nodes
-q --show_patches                    prints info about payches
-d --show_dag                        prints info about dag
-c --check                           performs various checks
-o <val> --nexus_file <val>          filename of the nexus output file
-p <val> --ply_file <val>            filename of the ply output file
-s <val> --size <val>                size in MegaBytes of the final file
                                     [requires -E]
-e <val> --error <val>               remove nodes below this error from the
-t <val> --triangles <val>           drop nodes until total number of triangles
                                     is < triangles [about double final
-l --last level                      remove nodes from last level
-z --compress                        compress patches
-Z <val> --compresslib <val>         pick among meco or corto compression libs,
                                     corto default
-v <val> --vertex quantization <val> absolute side of compression quantization
-V <val> --vertex bits <val>         number of bits in vertex coordinate when
-Y <val> --luma_bits <val>           quantization of luma channel (default 6)
-C <val> --chroma_bits <val>         quantization of chroma channel (default 6)
-A <val> --alha_bits <val>           quantization of alpha channel (default 5)
-N <val> --normal_bits <val>         quantization of normals (default 10)
-T <val> --tex_bits <val>            quantization of textures (default 0.25
-Q <val> --quantization_factor <val> quantization as a factor of error (default
-E <val> --recompute_error <val>     recompute errors [average, quadratic,
-m <val> --matrix <val>              multiply by matrix44 in format a:b:c...
-M <val> --imatrix <val>             multiply by inverse of matrix44 in format


Usage: nxsview [ARGS] [-demgcvhwfip]

This is just a quick tool to visualize nexus models.

-d <val> --draw <val>      max number of triangles
-e <val> --error <val>     target error in pixels
-m <val> --ram <val>       max ram used (in Mb)
-g <val> --video <val>     max video ram used (in Mb)
-c <val> --cache <val>     max number of items in cache
-v <val> --fov <val>       field of view in degrees
-h <val> --height <val>    height of the window
-w <val> --width <val>     width of the window
-s --fullscreen            fullscreen mode
-b --backface              backface culling
-o --occlusion             occlusion culling
-S --dontshare             do not use another thread for textures
-f <val> --fps <val>       target frames per second
-i <val> --instances <val> number of instances
-a --autopositioning       distribute models ina a grid
-p <val> --prefetch <val>  amount of node prefetching in prioritizer


This multiresolution library is designed to draw geometry in WebGL at the appropriate resolution given point view (context and sharers needs to be provided externally, so that it's easy to integrate into your viewer (see three.js below on how it is done).

var nexus = new Nexus.Instance(gl);  //webgl context is needed;
nexus.onLoad = function() {
	var mesh = nexus.mesh;
	//center and scale for the model
	var scale = 1/mesh.sphere.radius;
	var position =;
	//information about components of the nexus are accessible
	var hasNormals = mesh.vertex.normal;
	var hasColors = mesh.vertex.color;
	var hasUv = mesh.vertex.texCoord;
	var hasFaces = mesh.face.index;

//when additional geometry is avalable call your rendering function
nexus.onUpdate = function() {

	//setup a program (for example in three.js)
	var program = renderer.context.getParameter(gl.CURRENT_PROGRAM);

	//tell nexus to which attribute location binds it's attribute
	nexus.attributes['position'] = renderer.context.getAttribLocation(program, "position");
	nexus.attributes['normal'] = renderer.context.getAttribLocation(program, "normal");
	nexus.attributes['color'] = renderer.context.getAttribLocation(program, "color");
	nexus.attributes['uv'] = renderer.context.getAttribLocation(program, "uv");

	nexus.updateView([0, 0, width, height], projectionMatrix, modelViewMatrix);


A loader for three.js is available: html/js/nexus_three.js.

See demo.html source code for a basic implementation

var renderer = new THREE.WebGLRenderer();
var scene = new THREE.Scene();

var nexus_obj = new NexusObject("monreale.nxz", renderer, render);

function render() {
	renderer.render( scene, camera );


Multiresolution structures for interactive visualization of very large 3D datasets[20Mb]
Federico Ponchio
Phd Thesis

Batched Multi Triangulation
Paolo Cignoni, Fabio Ganovelli, Enrico Gobbetti, Fabio Marton, Federico Ponchio, Roberto Scopigno Proceedings IEEE Visualization, page 207-214 - October 2005

Adaptive TetraPuzzles: Efficient Out-of-Core Construction and Visualization of Gigantic Multiresolution Polygonal Models
P. Cignoni, F. Ganovelli, E. Gobbetti, F. Marton, F. Ponchio, R. Scopigno
ACM Trans. on Graphics, vol. 23(3), August 2004, pp. 796-803, (Siggraph '04)

BDAM: Batched Dynamic Adaptive Meshes for High Performance Terrain Visualization
P.Cignoni, F.Ganovelli, E. Gobbetti, F.Marton, F. Ponchio, R. Scopigno
Computer Graphics Forum, 22(3), Sept. 2003, pp.505-514.

Interactive Rendering of Dynamic Geometry
F. Ponchio, K. Hormann
IEEE Transaction on Visualization and Computer Graphics, Volume 14, Number 4, page 914--925 - Jul 2008

Fast decompression for web-based view-dependent 3D rendering
F. Ponchio, M. Dellepiane
Web3D 2015. Proceedings of the 20th International Conference on 3D Web Technology, pages 199-207

Support and thanks

Thanks, support: VCG, Informatic department in TU Clausthal, 3D-COFORM. also to Kai Hormann for having me write the thesis :)