sdrangel/plugins/feature/map/Cesium/Scene/ModelExperimental/CustomShaderGuide
Jon Beniston 72980c691d Add Cesium 2022-02-04 20:41:22 +00:00
..
README.md Add Cesium 2022-02-04 20:41:22 +00:00

README.md

CustomShader Documentation

Note: This README is stored in ModelExperimental/ temporarily while this is an experimental feature. In the future, this may move to the Documentation/ directory.

Constructor

var customShader = new Cesium.CustomShader({
  // Any custom uniforms the user wants to add to the shader.
  // these can be changed at runtime via customShader.setUniform()
  uniforms: {
    u_time: {
      value: 0, // initial value
      type: Cesium.UniformType.FLOAT
    },
    // Textures can be loaded from a URL, a Resource, or a TypedArray.
    // See the Uniforms section for more detail
    u_externalTexture: {
      value: new Cesium.TextureUniform({
        url: "http://example.com/image.png"
      }),
      type: Cesium.UniformType.SAMPLER_2D
    }
  }
  // Custom varyings that will appear in the custom vertex and fragment shader
  // text.
  varyings: {
    v_customTexCoords: Cesium.VaryingType.VEC2
  },
  // configure where in the fragment shader's materials/lighting pipeline the
  // custom shader goes. More on this below.
  mode: Cesium.CustomShaderMode.MODIFY_MATERIAL,
  // either PBR (physically-based rendering) or UNLIT depending on the desired
  // results.
  lightingModel: Cesium.LightingModel.PBR,
  // required when setting material.alpha in the fragment shader
  isTranslucent: true,
  // Custom vertex shader. This is a function from model space -> model space.
  // VertexInput is documented below
  vertexShaderText: `
    // IMPORTANT: the function signature must use these parameter names. This
    // makes it easier for the runtime to generate the shader and make optimizations.
    void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
        // code goes here. An empty body is a no-op.
    }
  `,
  // Custom fragment shader.
  // FragmentInput will be documented below
  // Regardless of the mode, this always takes in a material and modifies it in place.
  fragmentShaderText: `
    // IMPORTANT: the function signature must use these parameter names. This
    // makes it easier for the runtime to generate the shader and make optimizations.
    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
        // code goes here. e.g. to set the diffuse color to a translucent red:
        material.diffuse = vec3(1.0, 0.0, 0.0);
        material.alpha = 0.5;
    }
  `,
});

Applying A Custom Shader

Custom shaders can be applied to either 3D Tiles or ModelExperimental as follows:

var customShader = new Cesium.CustomShader(/* ... */);

// Applying to all tiles in a tileset.
var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
  url: "http://example.com/tileset.json",
  customShader: customShader
}));

// Applying to a model directly
var model = Cesium.ModelExperimental.fromGltf({,
  gltf: "http://example.com/model.gltf",
  customShader: customShader
});

Note: As of this writing, only tilesets that use the 3DTILES_content_gltf extension will support CustomShaders. Future releases will add support for other formats such as b3dm.

Uniforms

Custom Shaders currently supports the following uniform types:

UniformType GLSL type JS type
FLOAT float Number
VEC2 vec2 Cartesian2
VEC3 vec3 Cartesian3
VEC4 vec4 Cartesian4
INT int Number
INT_VEC2 ivec2 Cartesian2
INT_VEC3 ivec3 Cartesian3
INT_VEC4 ivec4 Cartesian4
BOOL bool Boolean
BOOL_VEC2 bvec2 Cartesian2
BOOL_VEC3 bvec3 Cartesian3
BOOL_VEC4 bvec4 Cartesian4
MAT2 mat2 Matrix2
MAT3 mat3 Matrix3
MAT4 mat4 Matrix4
SAMPLER_2D sampler2D TextureUniform

Texture Uniforms

Texture uniforms have more options, which have been encapsulated in the TextureUniform class. Textures can be loaded from a URL, a Resource or a typed array. Here are some examples:

var textureFromUrl = new Cesium.TextureUniform({
  url: "https://example.com/image.png",
});

var textureFromTypedArray = new Cesium.TextureUniform({
  typedArray: new Uint8Array([255, 0, 0, 255]),
  width: 1,
  height: 1,
  pixelFormat: Cesium.PixelFormat.RGBA,
  pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE,
});

// TextureUniform also provides options for controlling the sampler
var textureWithSampler = new Cesium.TextureUniform({
  url: "https://example.com/image.png",
  repeat: false,
  minificationFilter: Cesium.TextureMinificationFilter.NEAREST,
  magnificationFilter: Cesium.TextureMagnificationFilter.NEAREST,
});

Varyings

Varyings are declared in the CustomShader constructor. This automatically adds a line such as varying float v_userDefinedVarying; to the top of the GLSL shader.

The user is responsible for assigning a value to this varying in vertexShaderText and using it in fragmentShaderText. For example:

var customShader = new Cesium.CustomShader({
  // Varying is declared here
  varyings: {
    v_selectedColor: VaryingType.VEC3,
  },
  // User assigns the varying in the vertex shader
  vertexShaderText: `
    void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
        float positiveX = step(0.0, positionMC.x);
        v_selectedColor = mix(
            vsInput.attributes.color_0,
            vsInput.attributes.color_1,
            vsOutput.positionMC.x
        );
    }
  `,
  // User uses the varying in the fragment shader
  fragmentShaderText: `
    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
        material.diffuse = v_selectedColor;
    }
  `,
});

Custom Shaders supports the following varying types:

VaryingType GLSL type
FLOAT float
VEC2 vec2
VEC3 vec3
VEC4 vec4
MAT2 mat2
MAT3 mat3
MAT4 mat4

Custom Shader Modes

The custom fragment shader is configurable so it can go before/after materials or lighting. here's a summary of what modes are available.

Mode Fragment shader pipeline Description
MODIFY_MATERIAL (default) material -> custom shader -> lighting The custom shader modifies the results of the material stage
REPLACE_MATERIAL custom shader -> lighting Don't run the material stage at all, but procedurally generate it in the custom shader

In the above, "material" does preprocessing of textures, resulting in a czm_modelMaterial. This is mostly relevant for PBR, but even for UNLIT, the base color texture is handled.

VertexInput struct

An automatically-generated GLSL struct that contains attributes.

struct VertexInput {
    // Processed attributes. See the Attributes Struct section below.
    Attributes attributes;
    // In the future, metadata will be added here.
};

FragmentInput struct

This struct is similar to VertexInput, but there are a few more automatic variables for positions in various coordinate spaces.

struct FragmentInput {
    // Processed attribute values. See the Attributes Struct section below.
    Attributes attributes;
    // In the future, metadata will be added here.
};

Attributes Struct

The Attributes struct is dynamically generated given the variables used in the custom shader and the attributes available in the primitive to render.

For example, if the user uses fsInput.attributes.texCoord_0 in the shader, the runtime will generate the code needed to supply this value from the attribute TEXCOORD_0 in the model (where available)

If a primitive does not have the attributes necessary to satisfy the custom shader, a default value will be inferred where possible so the shader still compiles. Otherwise, the custom vertex/fragment shader portion will be disabled for that primitive.

The full list of built-in attributes are as follows. Some attributes have a set index, which is one of 0, 1, 2, ... (e.g. texCoord_0), these are denoted with an N.

Corresponding Attribute in Model variable in shader Type Available in Vertex Shader? Available in Fragment Shader? Description
POSITION positionMC vec3 Yes Yes Position in model coordinates
POSITION positionWC vec3 No Yes Position in world coordinates (WGS84 ECEF (x, y, z)). Low precision.
POSITION positionEC vec3 No Yes Position in eye coordinates.
NORMAL normalMC vec3 Yes No Unit-length normal vector in model coordinates. Only available in the vertex shader
NORMAL normalEC vec3 No Yes Unit-length normal vector in eye coordinates. Only available in the vertex shader
TANGENT tangentMC vec3 Yes No Unit-length tangent vector in model coordinates. This is always a vec3. For models that provide a w component, that is removed after computing the bitangent vector.
TANGENT tangentEC vec3 No Yes Unit-length tangent vector in eye coordinates. This is always a vec3. For models that provide a w component, that is removed after computing the bitangent vector.
NORMAL & TANGENT bitangentMC vec3 Yes No Unit-length bitangent vector in model coordinates. Only available when both normal and tangent vectors are available.
NORMAL & TANGENT bitangentEC vec3 No Yes Unit-length bitangent vector in eye coordinates. Only available when both normal and tangent vectors are available.
TEXCOORD_N texCoord_N vec2 Yes Yes N-th set of texture coordinates.
COLOR_N color_N vec4 Yes Yes N-th set of vertex colors. This is always a vec4; if the model does not specify an alpha value, it is assumed to be 1.
JOINTS_N joints_N ivec4 Yes Yes N-th set of joint indices
WEIGHTS_N weights_N vec4

Custom attributes are also available, though they are renamed to use lowercase letters and underscores. For example, an attribute called _SURFACE_TEMPERATURE in the model would become fsInput.attributes.surface_temperature in the shader.

czm_modelVertexOutput struct

This struct is built-in, see the documentation comment.

This struct contains the output of the custom vertex shader. This includes:

  • positionMC - The vertex position in model space coordinates. This struct field can be used e.g. to perturb or animate vertices. It is initialized to vsInput.attributes.positionMC. The custom shader may modify this, and the result is used to compute gl_Position.
  • pointSize - corresponds to gl_PointSize. This is only applied for models rendered as gl.POINTS, and ignored otherwise.

Implementation Note: positionMC does not modify the primitive's bounding sphere. If vertices are moved outside the bounding sphere, the primitive may be unintentionally culled depending on the view frustum.

czm_modelMaterial struct

This struct is a built-in, see the documentation comment. This is similar to czm_material from the old Fabric system, but slightly different fields as this one supports PBR lighting.

This struct serves as the basic input/output of the fragment shader pipeline stages. For example:

  • the material stage produces a material
  • the lighting stage takes in a material, computes lighting, and stores the result into material.diffuse
  • Custom shaders (regardless of where in the pipeline it is) takes in a material (even if it's a material with default values) and modifies this.