Визуализация в CesiumJS опирается на WebGL-рендеринг, где ключевая часть вычислений выполняется на GPU через GLSL-шейдеры. Каждый объект сцены проходит через вершинный и фрагментный этапы, на которых формируется геометрия и цвет пикселей.
Основные задачи шейдеров в CesiumJS:
CesiumJS предоставляет несколько уровней интеграции с шейдерами: от декларативных материалов до полного переопределения программ рендеринга.
Шейдерный код в CesiumJS распределяется по нескольким слоям:
Каждый слой решает свою задачу и может использоваться независимо или совместно с другими.
Материалы в CesiumJS представляют собой параметризованные шейдеры, описываемые через JavaScript-объекты. Они компилируются в GLSL автоматически.
Базовая структура материала:
const material = new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: new Cesium.Color(1.0, 0.0, 0.0, 1.0)
}
}
});
Fabric определяет:
Пример кастомного материала:
const pulseMaterial = new Cesium.Material({
fabric: {
type: 'Pulse',
uniforms: {
time: 0.0,
color: Cesium.Color.BLUE
},
source: `
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
float intensity = abs(sin(materialInput.st.s * 10.0 + time));
material.diffuse = color.rgb * intensity;
material.alpha = intensity;
return material;
}
`
}
});
В данном случае GLSL-функция czm_getMaterial
переопределяет поведение фрагментного шейдера.
Appearance используется при работе с Primitive API и позволяет задавать собственные шейдеры напрямую.
Базовая структура:
const appearance = new Cesium.PerInstanceColorAppearance({
fragmentShaderSource: `
varying vec4 v_color;
void main(void)
{
gl_FragColor = v_color;
}
`
});
Ключевые компоненты:
vertexShaderSource — логика вершинного шейдера;fragmentShaderSource — логика фрагментного
шейдера;renderState — настройки WebGL (blending, depth
test).Пример полного кастомного appearance:
const customAppearance = new Cesium.Appearance({
vertexShaderSource: `
attribute vec3 position;
void main() {
gl_Position = czm_modelViewProjection * vec4(position, 1.0);
}
`,
fragmentShaderSource: `
void main() {
gl_FragColor = vec4(0.2, 0.6, 1.0, 1.0);
}
`,
renderState: {
depthTest: {
enabled: true
},
blending: Cesium.BlendingState.ALPHA_BLEND
}
});
CesiumJS использует систему ShaderSource для сборки итогового шейдера из нескольких фрагментов.
ShaderSource позволяет:
Пример расширения:
const shaderSource = new Cesium.ShaderSource({
defines: ['CUSTOM_LIGHTING'],
sources: [
`
vec3 customLight(vec3 position) {
return normalize(position) * 0.5 + 0.5;
}
`
]
});
Эта система используется внутри материалов и appearance, обеспечивая модульность GLSL-кода.
Вершинный шейдер отвечает за трансформацию геометрии:
Пример кастомной деформации:
const vertexShader = `
attribute vec3 position;
uniform float amplitude;
void main()
{
vec3 displaced = position;
displaced.z += sin(position.x * 10.0) * amplitude;
gl_Position = czm_modelViewProjection * vec4(displaced, 1.0);
}
`;
Типовые задачи вершинных шейдеров:
Фрагментный шейдер определяет итоговый цвет пикселя.
Основные операции:
Пример градиентного шейдера:
const fragmentShader = `
varying vec2 v_st;
void main()
{
float t = v_st.t;
gl_FragColor = vec4(t, 0.3, 1.0 - t, 1.0);
}
`;
Часто используется система встроенных функций Cesium:
czm_materialInputczm_getDefaultMaterialczm_writeLogDepthczm_modelViewProjectionPrimitives — низкоуровневый слой CesiumJS, где шейдеры используются напрямую.
Пример:
const geometry = new Cesium.BoxGeometry({
vertexFormat: Cesium.VertexFormat.POSITION_ONLY
});
const instance = new Cesium.GeometryInstance({
geometry: geometry,
modelMatrix: Cesium.Matrix4.IDENTITY
});
const primitive = new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance({
flat: true
})
});
Appearance здесь определяет GLSL-поведение для всей геометрии.
3D Tiles используют не только шейдеры, но и declarative styling, который транслируется в GPU-логику.
Пример стиля:
tileset.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: [
['${height} > 1000', 'color("red")'],
['true', 'color("blue")']
]
}
});
Под капотом стиль преобразуется в GLSL-выражения, влияющие на фрагментный шейдер.
PostProcessStage позволяет применять шейдер ко всему изображению сцены.
Пример эффекта инверсии:
const invertStage = new Cesium.PostProcessStage({
fragmentShader: `
uniform sampler2D colorTexture;
void main()
{
vec4 color = texture2D(colorTexture, v_textureCoordinates);
gl_FragColor = vec4(1.0 - color.rgb, 1.0);
}
`
});
Типовые эффекты:
Uniform-переменные используются для передачи данных из JavaScript в GLSL.
Пример:
material.uniforms.time = performance.now() * 0.001;
В GLSL:
uniform float time;
Типы данных:
Текстуры являются ключевым элементом визуализации.
Пример использования:
uniform sampler2D image;
void main()
{
vec4 texColor = texture2D(image, v_st);
gl_FragColor = texColor;
}
Cesium автоматически управляет:
Cesium предоставляет набор встроенных GLSL-функций с префиксом
czm_.
Основные:
czm_getLambertDiffuse;czm_phongSpecular;czm_computePosition;czm_eyeToWindowCoordinates.Пример использования освещения:
vec3 normal = normalize(v_normal);
vec3 light = czm_sunDirectionWC;
float diffuse = max(dot(normal, light), 0.0);
Производительность критична в WebGL-среде.
Основные принципы:
Используемые подходы:
Частые ограничения:
Шейдеры должны учитывать интеграцию с Cesium render loop, иначе возможны артефакты и несогласованность кадров.