# `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

```js
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 vec3 positionMC) {
        // code goes here. e.g. for a no-op:
        return positionMC;
    }
  `,
  // 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:

```js
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:

```js
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:

```js
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 vec3 positionMC) {
        float positiveX = step(0.0, positionMC.x);
        v_selectedColor = mix(
            vsInput.attributes.color_0,
            vsInput.attributes.color_1,
            positionMC.x
        );
        return positionMC;
    }
  `,
  // 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.

```glsl
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.

```glsl
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_modelMaterial` struct

This one is a built-in, see the [documentation comment](../../../Shaders/Builtin/Structs/modelMaterial.glsl). 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.
