在 cesium 中,CustomShader 是一个相对底层的Api,基本深入开发 cesium 的同学多多少少会和这个 Api 有所接触。
具体使用文档请参考
本篇文章的主题是动态更新参数,在CustomShader中动态更新参数,需要了解 uniforms 对象。下表是 uniforms 对象支持的格式。
| 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 |
CustomShader 可以被用在 Cesium3DTileset、Model、等对象中,这里的 Model 也可以是从 layer 中获取的,例如 const modal = layer.getModel()
const customShader = new Cesium.CustomShader(/* ... */);
// Applying to all tiles in a tileset.
const tileset = await Cesium.Cesium3DTileset.fromUrl(
"http://example.com/tileset.json", {
customShader: customShader
});
viewer.scene.primitives.add(tileset);
// Applying to a model directly
const model = await Cesium.Model.fromGltfAsync({,
url: "http://example.com/model.gltf",
customShader: customShader
});
现在我们假设使用的是从 const modal = layer.getModel() 这里获取的 modal 对象,然后修改 modal 对象中的 customShader。
const textureUniformShader = new Cesium.CustomShader({
uniforms: {
u_texture: {
type: Cesium.UniformType.SAMPLER_2D,
value: new Cesium.TextureUniform({
url: urlBack,
repeat: false,
}),
},
u_time: {
type: Cesium.UniformType.FLOAT,
value: 0,
},
},
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
// v_normalMC = vsInput.attributes.positionMC;
// vsOutput.positionMC.y = 12.8 * vsInput.attributes.positionMC.y;
// vsOutput.positionMC.x = 12.8 * vsInput.attributes.positionMC.x;
// This model's x and y coordinates are in the range [0, 1], which
// conveniently doubles as UV coordinates.
vec2 uv = vsInput.attributes.positionMC.xy;
// Make the point cloud undulate in a complex wave that varies in
// both space and time. The amplitude is based on the original shape
// of the point cloud (which already is a wavy surface). The wave
// is computed relative to the center of the model, hence the
// transformations from [0, 1] -> [-1, 1] -> [0, 1]
float amplitude = 2.0 * vsInput.attributes.positionMC.z - 1.0;
float wave = amplitude * sin(2.0 * czm_pi * uv.x - 2.0 * u_time) * sin(u_time);
vsOutput.positionMC.z = 0.5 + 0.5 * wave;
// Make the points pulse in and out by changing their size
vsOutput.pointSize = 10.0 + 5.0 * sin(u_time);
}`,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material)
{
// Make the points circular instead of square
// float
// Make a sinusoid color palette that moves in the general direction
// of the wave, but at a different speed.
// Coefficients were chosen arbitrarily
vec2 uv = fsInput.attributes.positionMC.xy;
material.diffuse = 0.2 * fsInput.attributes.color_0.rgb;
material.diffuse += vec3(0.2, 0.3, 0.4) + vec3(0.2, 0.3, 0.4) * sin(2.0 * czm_pi * vec3(3.0, 2.0, 1.0) * uv.x - 3.0 * u_time);
}
`,
});
const startTime = performance.now();
viewer.scene.postUpdate.addEventListener(function () {
const elapsedTimeSeconds = (performance.now() - startTime) / 1000;
textureUniformShader.setUniform("u_time", elapsedTimeSeconds);
modal.customShader = textureUniformShader
});
通过使用 setUniform textureUniformShader.setUniform("u_time", elapsedTimeSeconds); 来修改和更新参数值。