mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-14 12:22:00 -05:00
288 lines
15 KiB
Markdown
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.
|