15 KiB
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 tovsInput.attributes.positionMC
. The custom shader may modify this, and the result is used to computegl_Position
.pointSize
- corresponds togl_PointSize
. This is only applied for models rendered asgl.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.