CesiumJS

repository·main·Indexed 12 days ago

https://github.com/cesiumgs/cesium

A high-performance JavaScript library for creating 3D globes and 2D maps in web browsers using WebGL. It supports open standards like 3D Tiles and is designed for visualizing massive, dynamic datasets. Version 1.144.0.

Tokens
194.5K
Snippets
552
Records
616
Agent score
96%

What's inside CesiumJS

  1. Overview of @cesium/engine

    main

    @cesium/engine is the core package of CesiumJS. It provides the fundamental rendering and data APIs required to create 3D globes and 2D maps in a web browser using WebGL.

    Key capabilities include:

    • Terrain and Imagery Engines: For rendering planetary surfaces.
    • 3D Tiles and 3D Models: Support for massive geospatial datasets and 3D assets.
    • Geometries and Vector Data: For drawing and managing spatial shapes.
  2. License information for CesiumJS

    main

    CesiumJS is licensed under the Apache License, Version 2.0.

    Key terms for users:

    • Permissions: You are granted a perpetual, worldwide, non-exclusive, royalty-free, and irrevocable copyright and patent license to use, modify, and distribute the software.
    • Redistribution Requirements: If you redistribute the work or derivative works, you must:
      • Provide a copy of the license.
      • Include prominent notices in modified files stating that you changed them.
      • Retain all original copyright, patent, trademark, and attribution notices.
      • Include a readable copy of any NOTICE file present in the original distribution.
    • Trademarks: This license does not grant permission to use the trade names, trademarks, or product names of the licensor, except for reasonable descriptions of the origin of the work.
    • Disclaimer: The work is provided on an "AS IS" basis, without warranties of any kind.
    Copyright 2011-2024 CesiumJS Contributors
    
                                     Apache License
                               Version 2.0, January 2004
                            http://www.apache.org/licenses/
  3. What is Fabric and how to use it

    main

    Fabric is a JSON schema used in CesiumJS to describe materials for objects like polygons, polylines, ellipsoids, and sensors. Materials define the visual appearance of these objects, ranging from simple colors to complex procedural patterns or combined textures.

    To apply a material, assign it to the object's material property. You can use the shorthand Cesium.Material.fromType(type) or provide a full Fabric JSON object via new Cesium.Material({ fabric: { ... } }).

    Each material has uniforms—input parameters that can be set during creation or modified later to update the appearance dynamically.

    // Using shorthand for a built-in material
    polygon.material = Cesium.Material.fromType("Color");
    
    // Using the full Fabric JSON schema
    polygon.material = new Cesium.Material({
      fabric: {
        type: "Color",
      },
    });
    
    // Modifying a uniform after creation
    polygon.material.uniforms.color = Cesium.Color.WHITE;
  4. Understand Custom Shader Modes

    main

    The mode property determines where your custom fragment shader is injected into the rendering pipeline. This affects whether you modify existing material properties or replace them entirely.

    ModeFragment shader pipelineDescription
    Cesium.CustomShaderMode.MODIFY_MATERIAL (default)material -> custom shader -> lightingThe custom shader modifies the results of the material stage (e.g., changing material.diffuse).
    Cesium.CustomShaderMode.REPLACE_MATERIALcustom shader -> lightingThe material stage is skipped. You must procedurally generate the material in your custom shader.

    In MODIFY_MATERIAL mode, the material stage performs preprocessing (like texture sampling) and provides a czm_modelMaterial object to your shader.

  5. Use Varyings in Custom Shaders

    main

    Varyings allow you to pass data from the vertex shader to the fragment shader. You must declare them in the CustomShader constructor using Cesium.VaryingType. Cesium will automatically handle the GLSL out and in declarations.

    Supported Varying Types:

    • FLOAT (float)
    • VEC2 (vec2)
    • VEC3 (vec3)
    • VEC4 (vec4)
    • MAT2 (mat2)
    • MAT3 (mat3)
    • MAT4 (mat4)

    Workflow:

    1. Declare the varying in the varyings object of the constructor.
    2. Assign a value to the varying in vertexShaderText.
    3. Access the varying in fragmentShaderText.
    const customShader = new Cesium.CustomShader({
      varyings: {
        v_selectedColor: Cesium.VaryingType.VEC4,
      },
      vertexShaderText: `
        void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
            float positiveX = step(0.0, vsOutput.positionMC.x);
            v_selectedColor = mix(
                vsInput.attributes.color_0,
                vsInput.attributes.color_1,
                vsOutput.positionMC.x
            );
        }
      `,
      fragmentShaderText: `
        void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
            material.diffuse = v_selectedColor.rgb;
        }
      `,
    });
  6. Optimize GLSL shader performance

    main

    To ensure high performance in shaders, follow these best practices:

    • Minimize Computation: Compute expensive values in JavaScript and pass them as uniforms, or compute them per-vertex and pass them as varyings, rather than re-computing them per-fragment.
    • Use discard Sparingly: Using discard can disable early-z GPU optimizations.
    • Avoid Branching: Conditional logic (if-else) can disrupt GPU parallelism.
      • Branching on a uniform (e.g., if (czm_orthographicIn3D == 1.0)) is generally acceptable as the value is consistent across threads.
      • For non-trivial logic, use czm_branchFreeTernary to avoid performance bottlenecks caused by branching.

    Example: Replacing an if statement with czm_branchFreeTernary

    Instead of:

    if (sphericalLatLong.y >= czm_pi) {
      sphericalLatLong.y = sphericalLatLong.y - czm_twoPi;
    }

    Use:

    sphericalLatLong.y = czm_branchFreeTernary(sphericalLatLong.y < czm_pi, sphericalLatLong.y, sphericalLatLong.y - czm_twoPi);
  7. Use `materialInput` in Fabric components and source

    main

    The materialInput variable is available in both components and source definitions. It provides geometric and texture coordinate data for the current fragment.

    materialInput Fields

    NameTypeDescription
    sfloatA 1D texture coordinate.
    stvec22D texture coordinates.
    strvec33D texture coordinates.
    tangentToEyeMatrixmat3Transformation matrix from fragment tangent space to eye coordinates.
    positionToEyeECvec3Vector from fragment to eye in eye coordinates (magnitude is distance in meters).
    normalECvec3The fragment's normalized normal in eye coordinates.

    Usage Examples

    Visualize st texture coordinates:

    {
      components: {
        diffuse: "vec3(materialInput.st, 0.0)"
      }
    }

    Visualize the eye-coordinate normal:

    {
      components: {
        diffuse: "materialInput.normalEC"
      }
    }
    {
      components: {
        diffuse: "vec3(materialInput.st, 0.0)"
      }
    }
  8. Understand the CesiumJS release schedule and types

    main

    CesiumJS follows a regular monthly release cycle, occurring on the first workday of every month. There are three main types of releases:

    • Regular Monthly Release: The standard scheduled release.
    • Patch Release: Published ahead of the regular monthly release, typically to address significant regressions or issues with published dependency versions.
    • Prerelease: A tagged prerelease published ahead of the regular monthly release, typically used for internal testing.

    For specific upcoming dates and assigned release managers, refer to the ReleaseSchedule.md file.

  9. Use normalized, offset, and scaled metadata values

    main

    When metadata properties are defined in the glTF schema, CesiumJS automatically handles normalization, offsets, and scaling before the values reach your shader.

    • Normalization: If normalized: true is set, the property appears as a floating point type (float or vec3) with components in the range [0, 1] (unsigned) or [-1, 1] (signed).
    • Offset and Scale: If offset or scale are provided, they are applied automatically after normalization.

    Example Schema Configuration:

    "properties": {
      "temperatureCelsius": {
        "type": "SCALAR",
        "componentType": "UINT32",
        "normalized": true,
        "scale": 100
      }
    }

    In the shader, vsInput.metadata.temperatureCelsius will be a float in the range [0.0, 100.0].

    // Accessing a pre-scaled/normalized value
    float temp = fsInput.metadata.temperatureCelsius;
  10. Organize test files in the Specs directory

    main

    CesiumJS tests are located in the Specs directory and follow a structure that mirrors the Source directory.

    • Naming Convention: If a source file is Source/Core/Cartesian3.js, its corresponding test file is Specs/Core/Cartesian3Spec.js.
    • Structure: The directory hierarchy in Specs should match the hierarchy in Source.
    • Unit Testing: Tests are primarily unit tests targeting individual functions or classes. Even private classes (e.g., ShaderCache) are often tested individually in their own spec files.
  11. Manage WebGL resource lifecycles with destroy()

    main

    Because WebGL resources must be explicitly deleted, classes that manage these resources must implement destroy() and isDestroyed() methods.

    Key Rules:

    • Use destroyObject(this) within your destroy() implementation to handle cleanup.
    • Ownership Principle: Only destroy objects that you created. If a class receives an external object as a parameter, it should not destroy it; the owner of that object is responsible for its lifecycle.
    // Example of implementing a destroy method
    class SkyBox {
      destroy() {
        this._vertexArray = this._vertexArray && this._vertexArray.destroy();
        return destroyObject(this);
      }
    }
    
    // Usage pattern
    const primitive = new Primitive(/* ... */);
    expect(content.isDestroyed()).toEqual(false);
    primitive.destroy();
    expect(content.isDestroyed()).toEqual(true);