Skip to content

Nuclideon/CesiumIntegration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Nuclideon udSDK for CesiumJS

Drop-in CesiumJS integration for Nuclideon's udSDK — render UDS point clouds inside a Cesium Viewer with depth correctly interleaving against Cesium-rendered terrain, 3D Tiles, and primitives.

Language:              Javascript / HTML
Type:                  Integration
Contributor:           Nuclideon Development Team <info@nuclideon.com>
Organization:          Nuclideon, https://nuclideon.com
Date:                  2026-05-22
Cesium Versions:       1.100+ (UMD build); tested against 1.141

Quick start

<script src="https://cesium.com/downloads/cesiumjs/releases/1.141/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.141/Build/Cesium/Widgets/widgets.css" rel="stylesheet" />
<script src="https://nuclideon.com/cdn/integrations/cesium/1.0.0/udsdk-cesium.js"></script>

<div id="cesiumContainer" style="width:100%;height:100vh"></div>
<script>
  const viewer = new Cesium.Viewer("cesiumContainer", { /* ... */ });

  udSDKCesium.attach(viewer, {
    clientName: "Acme Portal",
    models: ["https://my-bucket.s3.amazonaws.com/site.uds"],
  });
</script>

A worked example lives in demo.html.

Requirements

  • CesiumJS 1.100+ on the page as the Cesium global (UMD build, not the ES module build). Tested against 1.141.
  • Host page must be cross-origin isolated — udSDK is a threaded emscripten build and needs SharedArrayBuffer. Set these on the page response:
    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: credentialless    (or require-corp)
    
    Verify at runtime: window.crossOriginIsolated === true.
  • A Nuclideon udCloud account to sign in.

API

udSDKCesium.attach(viewer, opts) returns an EventTarget controller.

Options

Option Default Notes
clientName "cesium-<hostname>" OAuth consent app name
models [] array of url strings or {url, zOffset, zone, classification, flyTo}
signInUI "auto" "auto" shows the built-in box; false to BYO
signInLabel "Sign in to udCloud" button text
autoEnable true make the udSDK primitive visible immediately
autoFlyTo true fly the camera to the first loaded model
tryDomainLogin "auto" try silent SSO before falling back to OAuth popup
serverAddress (default udCloud) override for staging / self-hosted / regional
baseUrl derived from the script's own URL where to fetch udSDKjs.* siblings
onStatus null emscripten loader status callback

Controller

  • signIn()Promise. Must be triggered from a user gesture.
  • loadModel(spec)Promise<{handle, slot}>. spec is a url string or {url, zOffset, zone, classification, flyTo}.
  • enabled — show/hide the udSDK primitive.
  • signedIn, viewer, primitive, ready.
  • destroy() — remove primitive + UI.

Events

Event detail
ready
signed-in { method: "oauth" | "domain" }
model-loaded { url, handle, slot }
model-error { url, code, error }
sign-in-error { code, error }
error { error }

Local development

A tiny static server is included that issues the required COOP/COEP headers so the demo runs locally without setting up nginx/Caddy/etc.:

node serve.js
# http://localhost:8080/demo.html

How it works

  1. Bootstrap. udSDK is a threaded emscripten build, which means three non-obvious things have to happen when loading it cross-origin:

    • Module.locateFile points emscripten at the CDN base so it fetches udSDKjs.wasm from there instead of the page's origin.
    • The pthread pool spawns workers via new Worker(scriptUrl), which browsers refuse for cross-origin URLs regardless of CORS. The wrapper fetches udSDKjs.js as text, wraps it in a Blob, and hands the resulting same-origin Blob URL to emscripten via Module.mainScriptUrlOrBlob.
    • The page has to be cross-origin isolated (see Requirements) so SharedArrayBuffer is exposed.
  2. Sign-in. Tries udSDKJS_CreateSharedFrom_udCloud(name, null) first — a silent domain auth that succeeds if the browser already has a session with the configured udCloud server (typically via corporate SSO). If that fails, the built-in sign-in box opens an OAuth popup from a user gesture and finishes via udSDKJS_ConnectStart + udSDKJS_ConnectComplete.

  3. Per-frame render. A custom Primitive is added to viewer.scene.primitives. Its update(), each frame:

    • Resizes udSDK's offscreen scene if the canvas changed.
    • Pushes Cesium's viewMatrix + projectionMatrix into udSDK.
    • Calls udSDKJS_RenderQueue().
    • Copies udSDK's colour + depth buffers into two Cesium-managed GL textures.
    • Submits a screen-space DrawCommand that samples them. The fragment shader unprojects each sample's depth, computes world-space distance from the camera, and writes it through czm_writeLogDepth — so udSDK fragments depth-test correctly against everything else Cesium renders.
  4. Depth-buffer packing. udSDK delivers the depth buffer as raw IEEE-754 little-endian float32 bytes. The wrapper uploads it as an RGBA8 texture (4 bytes per pixel == 1 float per pixel) and decodes back to float in the shader. This avoids requiring R32F renderable-texture support on the Cesium side.

  5. Asyncify yield handling. udSDK's wasm uses emscripten Asyncify and yields by throwing the literal string "unwind". If that escapes into Cesium's render loop, Cesium catches it as a fatal renderError and stops rendering for good. The primitive's update() catches it locally and drops the frame instead — the last good colour/depth buffer stays bound on the textures so it's visually unnoticeable.

Limitations

  • Single-instance only. udSDK's render state is process-global, so one attach() per page.
  • No WebGL context-loss recovery. Colour/depth textures aren't recreated after a lost context. Reload the page.
  • WebGL2 required. The shader is GLSL 3.00 ES. Modern Cesium runs WebGL2 by default, but older Cesium pre-1.95 or a forced-WebGL1 context will not work.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors