sdrangel/plugins/feature/map/Cesium/Scene/ModelExperimental/CustomShaderGuide/README.md

288 lines
15 KiB
Markdown

# `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 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:
```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 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.
```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_modelVertexOutput` struct
This struct is built-in, see the [documentation comment](../../../Shaders/Builtin/Structs/modelVertexOutput.glsl).
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](../../../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.