CustomShader
DocumentationNote: This README is stored in ModelExperimental/
temporarily while
this is an experimental feature. In the future, this may move to the
Documentation/
directory.
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: `
void vertexMain(VertexInput vsInput, inout vec3 position) {
// code goes here. e.g. for a no-op:
return position;
}
`,
// Custom fragment shader.
// FragmentInput will be documented below
// Regardless of the mode, this always takes in a material and modifies it in place.
fragmentShaderText: `
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;
}
`,
});
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.
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 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 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 vec3 position) {
float positiveX = step(0.0, position.x);
v_selectedColor = mix(
vsInput.attributes.color_0,
vsInput.attributes.color_1,
position.x
);
return position;
}
`,
// 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 |
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
structAn automatically-generated GLSL struct that contains attributes.
// this struct represents the raw attribute values.
struct Attributes {
// required semantics
vec3 position; // model space position. Always present.
// optional semantics (added if available in the 3D model file)
vec3 normal; // corresponds to attribute with semantic "NORMAL"
vec3 tangent;
vec2 texCoord_0;
// etc.
// custom attribues
vec3 custom_attribute; // corresponds to attribute "_CUSTOM_ATTRIBUTE"
};
struct VertexInput {
// raw attribute values
Attributes attributes;
// in the future we may add another struct for derived attributes (e.g. positionEC)
};
FragmentInput
structThis struct is similar to VertexInput
, but there are a few more automatic
variables for positions in various coordinate spaces.
// this struct represents the raw attributes from the 3D model file. The
// varyings required to make this work are handled automatically.
struct Attributes {
// required semantics
vec3 position; // Raw model space position. always present as POSITION is required
// optional semantics (added if available in the 3D model file)
vec3 normal; // corresponds to attribute with semantic "NORMAL"
vec3 tangent;
vec2 texCoord_0;
// etc.
// custom attribues
vec3 custom_attribute; // corresponds to attribute "_CUSTOM_ATTRIBUTE"
};
struct FragmentInput {
// raw attribute values interpolated (but not normalized) from varyings.
Attributes attributes;
vec3 positionMC; // model space
vec3 positionWC; // World coords (ECEF). Low precision.
vec3 positionEC; // Eye coordinates
};
czm_modelMaterial
structThis one 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:
material.diffuse