当前位置: 首页 > news >正文

学习Cesium自定义材质

Cesium自定义材质系统详解

📊 材质系统流程图

材质系统入口
内置材质
自定义材质
ColorMaterialProperty
ImageMaterialProperty
PolylineGlowMaterialProperty
其他内置材质...
Material.fromType
新建Material对象
定义fabric结构
uniforms定义
source着色器代码
传递动态参数
GLSL着色器代码
实时更新材质
GPU渲染

🧬 Cesium材质系统基础

Cesium的材质系统允许自定义实体的外观。材质(Material)定义了如何渲染Entity图形组件的表面,包括颜色、纹理、光照等特性。

// 基本材质创建模式
const simplePolygon = viewer.entities.add({polygon: {hierarchy: Cesium.Cartesian3.fromDegreesArray([116.39, 39.9,116.5, 39.9,116.5, 40.0,116.39, 40.0]),// ⭐最简单的材质 - 纯色material: Cesium.Color.RED.withAlpha(0.5)}
});

🎨 内置材质类型及使用

1. 颜色材质(Color)

// 颜色材质 - 最基础
const colorEntity = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(116.3, 39.8, 116.4, 39.9),material: new Cesium.ColorMaterialProperty(Cesium.Color.BLUE.withAlpha(0.5))}
});

2. 图像材质(Image)

// 图像材质
const imageEntity = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(116.3, 39.7, 116.4, 39.8),material: new Cesium.ImageMaterialProperty({image: './images/texture.jpg',repeat: new Cesium.Cartesian2(4, 4), // 水平和垂直重复次数color: Cesium.Color.WHITE // 可选颜色调整})}
});

3. 条纹材质(Stripe)

// 条纹材质
const stripeEntity = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(116.3, 39.6, 116.4, 39.7),material: new Cesium.StripeMaterialProperty({evenColor: Cesium.Color.WHITE,oddColor: Cesium.Color.BLACK,repeat: 32, // 条纹数量orientation: Cesium.StripeOrientation.HORIZONTAL // 方向})}
});

4. 棋盘格材质(Checkerboard)

// 棋盘格材质
const checkerboardEntity = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(116.3, 39.5, 116.4, 39.6),material: new Cesium.CheckerboardMaterialProperty({evenColor: Cesium.Color.RED,oddColor: Cesium.Color.YELLOW,repeat: new Cesium.Cartesian2(8, 8) // 水平和垂直格子数})}
});

5. 网格材质(Grid)

// 网格材质
const gridEntity = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(116.3, 39.4, 116.4, 39.5),material: new Cesium.GridMaterialProperty({color: Cesium.Color.GREEN,cellAlpha: 0.2, // 单元格透明度lineCount: new Cesium.Cartesian2(8, 8), // 线条数量lineThickness: new Cesium.Cartesian2(2.0, 2.0) // 线条粗细})}
});

6. 折线发光材质(PolylineGlow)

// 发光折线材质
const glowLineEntity = viewer.entities.add({polyline: {positions: Cesium.Cartesian3.fromDegreesArray([116.2, 39.9,116.3, 39.8,116.4, 39.9]),width: 10,material: new Cesium.PolylineGlowMaterialProperty({glowPower: 0.2, // 发光强度(0到1)color: Cesium.Color.BLUE // 发光颜色})}
});

7. 折线箭头材质(PolylineArrow)

// 箭头折线材质
const arrowEntity = viewer.entities.add({polyline: {positions: Cesium.Cartesian3.fromDegreesArray([116.2, 39.7,116.4, 39.7]),width: 10,material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.PURPLE)}
});

8. 折线虚线材质(PolylineDash)

// 虚线折线材质
const dashLineEntity = viewer.entities.add({polyline: {positions: Cesium.Cartesian3.fromDegreesArray([116.2, 39.6,116.4, 39.6]),width: 5,material: new Cesium.PolylineDashMaterialProperty({color: Cesium.Color.CYAN,dashLength: 16.0, // 虚线长度dashPattern: 255 // 虚线模式(二进制)})}
});

🔮 自定义材质创建

1. 基本自定义材质结构

// ⭐基本自定义材质结构
const customMaterial = new Cesium.Material({fabric: {// 材质类型type: 'MyCustomMaterial',// 着色器统一变量uniforms: {color: new Cesium.Color(1.0, 0.0, 0.0, 1.0),time: 0,speed: 1.0},// GLSL着色器代码source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);// 自定义着色逻辑material.diffuse = color.rgb;material.alpha = color.a;return material;}`},// 半透明材质translucent: function() {return this.uniforms.color.alpha < 1.0;}
});

2. 使用自定义材质

// 将自定义材质应用到实体
const customEntity = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(116.5, 39.9, 116.6, 40.0),material: customMaterial}
});// 更新材质参数
viewer.scene.preRender.addEventListener((scene, time) => {customMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);
});

🎭 实用自定义材质示例

1. 脉冲扩散材质

// ⭐脉冲扩散波材质
const pulseMaterial = new Cesium.Material({fabric: {type: 'PulseCircle',uniforms: {color: new Cesium.Color(0.0, 1.0, 1.0, 1.0),time: 0,pulseSpeed: 1.0,pulseCount: 3},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);// 计算距中心距离vec2 center = vec2(0.5, 0.5);float dist = distance(materialInput.st, center);// 创建多个脉冲波float wave = abs(sin(dist * 10.0 * pulseCount - time * pulseSpeed));// 随距离衰减float alpha = wave * (1.0 - dist * 2.0);alpha = clamp(alpha, 0.0, 1.0);material.diffuse = color.rgb;material.alpha = alpha * color.a;return material;}`},translucent: function() {return true;}
});// 应用材质到圆形
const pulseCircle = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(116.39, 39.9),ellipse: {semiMajorAxis: 1000,semiMinorAxis: 1000,material: pulseMaterial,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND}
});// 更新时间
viewer.scene.preRender.addEventListener((scene, time) => {pulseMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);
});

2. 雷达扫描材质

// ⭐雷达扫描材质
const radarMaterial = new Cesium.Material({fabric: {type: 'Radar',uniforms: {color: new Cesium.Color(0.0, 1.0, 0.0, 1.0),time: 0,scanSpeed: 1.0},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;vec2 center = vec2(0.5, 0.5);// 计算角度float angle = atan(st.y - center.y, st.x - center.x);// 标准化角度到0-1float normalizedAngle = (angle / czm_pi + 1.0) * 0.5;// 扫描线角度float scanAngle = fract(time * scanSpeed * 0.1);// 扫描线宽度float scanWidth = 0.08;// 创建扫描线效果float scanLine = smoothstep(scanAngle - scanWidth, scanAngle, normalizedAngle) * smoothstep(normalizedAngle, scanAngle + 0.02, normalizedAngle + scanWidth);// 距离中心渐变float dist = distance(st, center);float circle = 1.0 - smoothstep(0.0, 0.5, dist);// 创建雷达网格float rings = 0.3 * (1.0 - abs(sin(dist * 20.0 - time * 0.5)));float grid = max(0.0, rings);// 合并效果float alpha = max(scanLine * 0.8, grid * 0.2) * circle;material.diffuse = color.rgb;material.alpha = alpha;// 扫描线区域使用更亮的颜色material.emission = scanLine * color.rgb * 2.0;return material;}`},translucent: function() {return true;}
});// 应用到圆形
const radarCircle = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(116.5, 39.9),ellipse: {semiMajorAxis: 1000,semiMinorAxis: 1000,material: radarMaterial,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND}
});// 更新时间
viewer.scene.preRender.addEventListener((scene, time) => {radarMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);
});

3. 流动线材质

// ⭐流动线材质
const flowingLineMaterial = new Cesium.Material({fabric: {type: 'FlowingLine',uniforms: {color: new Cesium.Color(1.0, 1.0, 0.0, 1.0),time: 0,speed: 3.0,percent: 0.1,gradient: 0.5},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);// 获取纹理坐标vec2 st = materialInput.st;// 创建流动效果float t = fract(time * speed * 0.1);float alpha = smoothstep(t - percent, t, st.s) * smoothstep(st.s, t + percent, st.s);// 应用渐变alpha = pow(alpha, gradient);material.diffuse = color.rgb;material.alpha = alpha;return material;}`},translucent: function() {return true;}
});// 应用到折线
const flowingLine = viewer.entities.add({polyline: {positions: Cesium.Cartesian3.fromDegreesArray([116.3, 39.8,116.4, 39.9,116.5, 39.8,116.6, 39.9]),width: 8,material: flowingLineMaterial}
});// 更新时间
viewer.scene.preRender.addEventListener((scene, time) => {flowingLineMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);
});

4. 动态渐变色材质

// ⭐动态渐变色材质
const gradientMaterial = new Cesium.Material({fabric: {type: 'DynamicGradient',uniforms: {color1: new Cesium.Color(1.0, 0.0, 0.0, 1.0),color2: new Cesium.Color(0.0, 0.0, 1.0, 1.0),time: 0,speed: 1.0,horizontal: true},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;// 选择水平或垂直渐变float gradient = horizontal ? st.s : st.t;// 添加动态波动效果gradient = gradient + 0.1 * sin(st.t * 10.0 + time * speed);// 限制在0-1范围gradient = clamp(gradient, 0.0, 1.0);// 颜色混合vec4 color = mix(color1, color2, gradient);material.diffuse = color.rgb;material.alpha = color.a;return material;}`},translucent: function() {return this.uniforms.color1.alpha < 1.0 || this.uniforms.color2.alpha < 1.0;}
});// 应用到多边形
const gradientPolygon = viewer.entities.add({polygon: {hierarchy: Cesium.Cartesian3.fromDegreesArray([116.6, 39.8,116.7, 39.8,116.7, 39.9,116.6, 39.9]),material: gradientMaterial,extrudedHeight: 500 // 创建3D效果}
});// 更新时间
viewer.scene.preRender.addEventListener((scene, time) => {gradientMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);
});

5. 热力图材质

// ⭐热力图材质
const heatmapMaterial = new Cesium.Material({fabric: {type: 'Heatmap',uniforms: {points: [0.3, 0.3, 0.7, 0.5, 0.5, 0.7], // x1,y1,x2,y2,x3,y3intensities: [1.0, 0.8, 0.6],           // 强度值radius: 0.15,                           // 点半径time: 0},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;// 热力点数量int pointCount = intensities.length;// 计算热力值float heat = 0.0;for (int i = 0; i < 20; i++) {if (i >= pointCount) break;// 获取点位置vec2 point = vec2(points[i*2], points[i*2+1]);// 计算距离float dist = distance(st, point);// 贡献热力值float pointHeat = intensities[i] * smoothstep(radius, 0.0, dist);heat += pointHeat;}// 限制最大值heat = clamp(heat, 0.0, 1.0);// 生成脉动效果heat *= 0.8 + 0.2 * sin(time * 2.0);// 颜色映射vec3 color;if (heat < 0.3) {color = mix(vec3(0,0,1), vec3(0,1,1), heat / 0.3);} else if (heat < 0.6) {color = mix(vec3(0,1,1), vec3(1,1,0), (heat - 0.3) / 0.3);} else {color = mix(vec3(1,1,0), vec3(1,0,0), (heat - 0.6) / 0.4);}material.diffuse = color;material.alpha = heat * 0.7;return material;}`},translucent: function() {return true;}
});// 应用到矩形
const heatmapRectangle = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(116.7, 39.7, 116.8, 39.8),material: heatmapMaterial,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND}
});// 更新时间和点位置
viewer.scene.preRender.addEventListener((scene, time) => {const seconds = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);heatmapMaterial.uniforms.time = seconds;// 动态更新热力点位置const points = [];const intensities = [];// 创建3个移动的热力点for (let i = 0; i < 3; i++) {const angle = seconds * 0.2 + i * Math.PI * 2 / 3;const r = 0.2;points.push(0.5 + r * Math.cos(angle));points.push(0.5 + r * Math.sin(angle));intensities.push(0.7 + 0.3 * Math.sin(seconds + i));}heatmapMaterial.uniforms.points = points;heatmapMaterial.uniforms.intensities = intensities;
});

📝 GLSL着色器基础知识

GLSL(OpenGL着色语言)是自定义材质的核心,以下是常用概念:

// 材质输入结构
// materialInput.st - 纹理坐标(0-1)
// materialInput.normalEC - 法线向量
// materialInput.positionToEyeEC - 到相机的向量// 材质输出结构
// material.diffuse - 漫反射颜色(rgb)
// material.specular - 镜面反射颜色
// material.shininess - 光泽度
// material.normal - 法线
// material.emission - 自发光
// material.alpha - 透明度// 常用GLSL函数
// mix(a, b, t) - 线性插值
// smoothstep(edge0, edge1, x) - 平滑过渡
// clamp(x, min, max) - 范围限制
// distance(p1, p2) - 计算距离
// length(v) - 向量长度
// normalize(v) - 向量归一化
// dot(v1, v2) - 点积
// sin/cos/tan - 三角函数
// pow(x, y) - x的y次方
// fract(x) - 小数部分
// floor(x) - 向下取整

🛠️ 自定义材质工具类

// ⭐自定义材质管理器
class MaterialManager {constructor(viewer) {this.viewer = viewer;this.materials = new Map();}// 创建脉冲圆材质createPulseCircleMaterial(options = {}) {const material = new Cesium.Material({fabric: {type: 'PulseCircle',uniforms: {color: options.color || new Cesium.Color(0.0, 1.0, 1.0, 1.0),time: 0,pulseSpeed: options.speed || 1.0,pulseCount: options.count || 3},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 center = vec2(0.5, 0.5);float dist = distance(materialInput.st, center);float wave = abs(sin(dist * 10.0 * pulseCount - time * pulseSpeed));float alpha = wave * (1.0 - dist * 2.0);alpha = clamp(alpha, 0.0, 1.0);material.diffuse = color.rgb;material.alpha = alpha * color.a;return material;}`},translucent: function() {return true;}});const id = options.id || `pulse_${Date.now()}`;this.materials.set(id, material);// 更新时间if (!this._hasTimeUpdate) {this._hasTimeUpdate = true;this.viewer.scene.preRender.addEventListener((scene, time) => {const seconds = Cesium.JulianDate.secondsDifference(time, this.viewer.clock.startTime);// 更新所有材质this.materials.forEach(material => {if (material.uniforms.time !== undefined) {material.uniforms.time = seconds;}});});}return material;}// 创建雷达扫描材质createRadarMaterial(options = {}) {const material = new Cesium.Material({fabric: {type: 'Radar',uniforms: {color: options.color || new Cesium.Color(0.0, 1.0, 0.0, 1.0),time: 0,scanSpeed: options.speed || 1.0},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;vec2 center = vec2(0.5, 0.5);float angle = atan(st.y - center.y, st.x - center.x);float normalizedAngle = (angle / czm_pi + 1.0) * 0.5;float scanAngle = fract(time * scanSpeed * 0.1);float scanWidth = 0.08;float scanLine = smoothstep(scanAngle - scanWidth, scanAngle, normalizedAngle) * smoothstep(normalizedAngle, scanAngle + 0.02, normalizedAngle + scanWidth);float dist = distance(st, center);float circle = 1.0 - smoothstep(0.0, 0.5, dist);float rings = 0.3 * (1.0 - abs(sin(dist * 20.0 - time * 0.5)));float grid = max(0.0, rings);float alpha = max(scanLine * 0.8, grid * 0.2) * circle;material.diffuse = color.rgb;material.alpha = alpha;material.emission = scanLine * color.rgb * 2.0;return material;}`},translucent: function() {return true;}});const id = options.id || `radar_${Date.now()}`;this.materials.set(id, material);return material;}// 获取材质getMaterial(id) {return this.materials.get(id);}// 更新材质参数updateMaterial(id, uniformName, value) {const material = this.materials.get(id);if (material && material.uniforms[uniformName] !== undefined) {material.uniforms[uniformName] = value;return true;}return false;}// 移除材质removeMaterial(id) {return this.materials.delete(id);}
}// 使用示例
const materialManager = new MaterialManager(viewer);// 创建脉冲圆材质
const pulseMaterial = materialManager.createPulseCircleMaterial({id: 'pulse1',color: new Cesium.Color(1.0, 0.0, 0.0, 0.7),speed: 2.0,count: 5
});// 应用到实体
const pulseCircle = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(116.4, 39.9),ellipse: {semiMajorAxis: 1000,semiMinorAxis: 1000,material: pulseMaterial,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND}
});// 动态更新参数
setTimeout(() => {materialManager.updateMaterial('pulse1', 'color', new Cesium.Color(0.0, 0.0, 1.0, 0.7));materialManager.updateMaterial('pulse1', 'pulseSpeed', 4.0);
}, 5000);

🎯 实际应用场景

1. 动态区域监控

// ⭐动态监控区域材质
function createMonitoringZone(position, radius, options = {}) {// 创建监控区域材质const monitorMaterial = new Cesium.Material({fabric: {type: 'MonitoringZone',uniforms: {color: options.color || new Cesium.Color(0.0, 0.8, 1.0, 0.7),time: 0,alertLevel: options.alertLevel || 0.0, // 0.0-1.0pulseSpeed: options.pulseSpeed || 1.0},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;vec2 center = vec2(0.5, 0.5);float dist = distance(st, center);// 创建网格float grid = max(0.0, 0.3 * (1.0 - abs(sin(dist * 20.0 - time * 0.5))));// 创建边缘发光float edge = 1.0 - smoothstep(0.4, 0.5, dist);// 脉冲波float pulseWave = abs(sin(dist * 15.0 - time * pulseSpeed));float pulse = smoothstep(0.3, 1.0, pulseWave) * (1.0 - dist * 2.0);// 根据警报级别调整颜色vec3 baseColor = color.rgb;vec3 alertColor = vec3(1.0, 0.0, 0.0);vec3 finalColor = mix(baseColor, alertColor, alertLevel);// 警报模式下加快脉冲float alertPulse = 0.0;if (alertLevel > 0.0) {alertPulse = sin(time * 5.0 * alertLevel) * 0.5 + 0.5;}material.diffuse = finalColor;material.alpha = max(max(grid, pulse), edge * 0.7) * color.a;// 警报状态增加自发光material.emission = finalColor * alertPulse * alertLevel;return material;}`},translucent: function() {return true;}});// 创建监控区域实体const monitorZone = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(position[0], position[1]),ellipse: {semiMajorAxis: radius,semiMinorAxis: radius,material: monitorMaterial,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,outline: true,outlineColor: Cesium.Color.WHITE.withAlpha(0.3)},// 监控区域标签label: {text: options.name || '监控区域',font: '14px sans-serif',style: Cesium.LabelStyle.FILL_AND_OUTLINE,outlineWidth: 2,verticalOrigin: Cesium.VerticalOrigin.BOTTOM,pixelOffset: new Cesium.Cartesian2(0, -radius / 20),heightReference: Cesium.HeightReference.CLAMP_TO_GROUND}});// 更新时间viewer.scene.preRender.addEventListener((scene, time) => {monitorMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);});// 返回控制接口return {entity: monitorZone,setAlertLevel: function(level) {monitorMaterial.uniforms.alertLevel = Cesium.Math.clamp(level, 0.0, 1.0);},setPulseSpeed: function(speed) {monitorMaterial.uniforms.pulseSpeed = speed;},setColor: function(color) {monitorMaterial.uniforms.color = color;}};
}// 创建监控区域
const monitorZone1 = createMonitoringZone([116.4, 39.9], 1000, {name: '北京监控区域',color: new Cesium.Color(0.0, 0.7, 1.0, 0.7),pulseSpeed: 1.0
});// 模拟警报触发
let alertLevel = 0;
let alertIncreasing = true;setInterval(() => {if (alertIncreasing) {alertLevel += 0.05;if (alertLevel >= 1.0) {alertLevel = 1.0;alertIncreasing = false;}} else {alertLevel -= 0.05;if (alertLevel <= 0.0) {alertLevel = 0.0;alertIncreasing = true;}}// 更新警报级别monitorZone1.setAlertLevel(alertLevel);
}, 200);

2. 动态流向图

// ⭐流向图材质 - 可视化水流、交通等
function createFlowMapVisualization(coordinates, flowDirections, options = {}) {// 创建流向图材质const flowMaterial = new Cesium.Material({fabric: {type: 'FlowMap',uniforms: {flowMap: options.flowTexture || './images/flow_map.png',color: options.color || new Cesium.Color(0.0, 0.5, 1.0, 0.7),time: 0,speed: options.speed || 1.0,strength: options.strength || 0.5},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;// 采样流向图纹理float offset = time * speed;vec2 flowSample1 = texture2D(flowMap, st + vec2(offset, 0.0)).rg * 2.0 - 1.0;vec2 flowSample2 = texture2D(flowMap, st + vec2(-offset * 0.5, offset * 0.5)).rg * 2.0 - 1.0;// 混合多个采样方向vec2 flow = mix(flowSample1, flowSample2, 0.5) * strength;// 创建流动线效果float flowLine = abs(sin(st.s * 20.0 + st.t * 10.0 - time * 3.0));flowLine = smoothstep(0.7, 1.0, flowLine);// 随流向方向变化透明度float alpha = 0.2 + 0.6 * dot(flow, flow) + 0.2 * flowLine;// 边缘衰减alpha *= (1.0 - smoothstep(0.4, 0.5, distance(st, vec2(0.5))));material.diffuse = color.rgb;material.alpha = alpha * color.a;return material;}`},translucent: function() {return true;}});// 创建显示实体const flowEntity = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(coordinates[0], coordinates[1], coordinates[2], coordinates[3]),material: flowMaterial,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND}});// 更新时间viewer.scene.preRender.addEventListener((scene, time) => {flowMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);});// 返回控制接口return {entity: flowEntity,setSpeed: function(speed) {flowMaterial.uniforms.speed = speed;},setStrength: function(strength) {flowMaterial.uniforms.strength = strength;},setColor: function(color) {flowMaterial.uniforms.color = color;}};
}// 创建流向可视化
const flowMap = createFlowMapVisualization([116.3, 39.8, 116.5, 40.0], // 矩形范围[], // 流向数据(在实际应用中可从气象或交通数据生成){color: new Cesium.Color(0.0, 0.7, 1.0, 0.5),speed: 0.5,strength: 0.7}
);

3. 范围选区材质

// ⭐区域选择材质
function createSelectionAreaMaterial(options = {}) {const selectionMaterial = new Cesium.Material({fabric: {type: 'SelectionArea',uniforms: {color: options.color || new Cesium.Color(0.0, 1.0, 1.0, 0.6),time: 0,selected: options.selected || false},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;// 创建网格效果float gridX = abs(sin(st.s * 50.0));float gridY = abs(sin(st.t * 50.0));float grid = max(smoothstep(0.95, 1.0, gridX),smoothstep(0.95, 1.0, gridY)) * 0.5;// 创建边框效果float border = 0.0;if (st.s < 0.05 || st.s > 0.95 || st.t < 0.05 || st.t > 0.95) {border = 1.0;}// 创建选中脉冲效果float pulse = 0.0;if (selected) {pulse = abs(sin(time * 3.0)) * 0.3;// 加强边框border *= 1.0 + pulse;}// 组合所有效果float alpha = 0.2 + grid + border + pulse;material.diffuse = color.rgb;material.alpha = alpha * color.a;return material;}`},translucent: function() {return true;}});// 更新时间viewer.scene.preRender.addEventListener((scene, time) => {selectionMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);});return selectionMaterial;
}// 使用选区材质
function createSelectionPolygon(positions, options = {}) {// 创建材质const material = createSelectionAreaMaterial({color: options.color || new Cesium.Color(0.0, 1.0, 1.0, 0.6),selected: options.selected || false});// 创建选区多边形const polygon = viewer.entities.add({polygon: {hierarchy: positions instanceof Cesium.PolygonHierarchy ? positions : new Cesium.PolygonHierarchy(positions),material: material,height: options.height || 0,extrudedHeight: options.extrudedHeight,outline: true,outlineColor: Cesium.Color.WHITE}});// 返回控制接口return {entity: polygon,setSelected: function(selected) {material.uniforms.selected = selected;},setColor: function(color) {material.uniforms.color = color;}};
}// 示例使用 - 创建可选择区域
const areaPositions = Cesium.Cartesian3.fromDegreesArray([116.3, 39.9,116.4, 39.9,116.4, 40.0,116.3, 40.0
]);const selectionArea = createSelectionPolygon(areaPositions, {selected: false,color: new Cesium.Color(1.0, 1.0, 0.0, 0.6),extrudedHeight: 500
});// 点击切换选中状态
let selected = false;
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(click) {selected = !selected;selectionArea.setSelected(selected);// 改变选中颜色if (selected) {selectionArea.setColor(new Cesium.Color(0.0, 1.0, 0.5, 0.6));} else {selectionArea.setColor(new Cesium.Color(1.0, 1.0, 0.0, 0.6));}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

🎨 创建自定义着色器特效

1. 体积云材质

// ⭐体积云材质
function createVolumetricCloudMaterial() {return new Cesium.Material({fabric: {type: 'VolumetricCloud',uniforms: {cloudTexture: './images/noise.png',time: 0,speed: 0.01,brightness: 1.0,coverage: 0.6,frequency: 3.0},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;// 采样噪声纹理作为云层形状vec2 offset = vec2(time * speed, time * speed * 0.5);float noise1 = texture2D(cloudTexture, st + offset).r;float noise2 = texture2D(cloudTexture, st * 2.0 - offset * 1.5).r;float noise3 = texture2D(cloudTexture, st * 4.0 + offset * 0.7).r;// 多频率混合 (FBM - 分形布朗运动)float fbm = noise1 * 0.5 + noise2 * 0.3 + noise3 * 0.2;// 形成云朵形状float cloud = smoothstep(coverage, coverage + 0.2, fbm);// 添加体积感float density = cloud * brightness;density = pow(density, 1.5); // 增强对比度// 边缘羽化density *= 1.0 - smoothstep(0.4, 0.5, distance(st, vec2(0.5)));material.diffuse = vec3(1.0);material.alpha = density;return material;}`},translucent: function() {return true;}});
}// 创建云团
function createCloudGroup(positions, options = {}) {const clouds = [];// 创建多个云团for (let i = 0; i < positions.length; i++) {const position = positions[i];const size = options.sizes ? options.sizes[i] : 2000 + Math.random() * 3000;// 创建云材质const cloudMaterial = createVolumetricCloudMaterial();// 调整参数cloudMaterial.uniforms.speed = 0.005 + Math.random() * 0.01;cloudMaterial.uniforms.coverage = 0.4 + Math.random() * 0.3;cloudMaterial.uniforms.brightness = 0.7 + Math.random() * 0.3;// 创建云实体const cloud = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 1000 + Math.random() * 1000),ellipsoid: {radii: new Cesium.Cartesian3(size, size, size * 0.5),material: cloudMaterial}});clouds.push({entity: cloud,material: cloudMaterial});}// 更新时间viewer.scene.preRender.addEventListener((scene, time) => {const seconds = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);// 更新所有云材质clouds.forEach(cloud => {cloud.material.uniforms.time = seconds;});});return clouds;
}// 在随机位置创建云团
const cloudPositions = [];
for (let i = 0; i < 10; i++) {cloudPositions.push([116.3 + Math.random() * 0.5,39.8 + Math.random() * 0.3,1000 + Math.random() * 1000]);
}const clouds = createCloudGroup(cloudPositions);

2. 水面材质

// ⭐水面材质
function createWaterMaterial() {return new Cesium.Material({fabric: {type: 'Water',uniforms: {normalMap: './images/waterNormals.jpg',time: 0,waveStrength: 0.2,waveSpeed: 0.06,reflectivity: 0.5,waterColor: new Cesium.Color(0.0, 0.3, 0.6, 1.0)},source: `czm_material czm_getMaterial(czm_materialInput materialInput) {czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;// 创建波浪动画vec2 direction1 = vec2(1.0, 0.0);vec2 direction2 = vec2(0.0, 1.0);vec2 uv1 = st + time * waveSpeed * direction1;vec2 uv2 = st + time * waveSpeed * direction2 * 0.8;// 采样法线贴图vec3 normal1 = texture2D(normalMap, uv1).rgb * 2.0 - 1.0;vec3 normal2 = texture2D(normalMap, uv2).rgb * 2.0 - 1.0;// 混合两个法线方向vec3 normal = normalize(normal1 + normal2);// 扭曲因子float distortion = length(normal.xy) * waveStrength;// 计算反射vec3 viewDir = normalize(materialInput.positionToEyeEC);vec3 reflectDir = reflect(-viewDir, normal);// 菲涅尔效果float fresnel = pow(1.0 - dot(viewDir, normal), 3.0) * reflectivity;// 水色与反射混合vec3 color = mix(waterColor.rgb, vec3(1.0), fresnel);// 加入波光float specular = pow(max(dot(reflectDir, normalize(vec3(0.1, 0.1, 1.0))), 0.0), 32.0);color += specular * 0.3;material.diffuse = color;material.alpha = 0.8;// 更新法线以进行光照计算material.normal = normal;return material;}`},translucent: function() {return true;}});
}// 创建水面
function createWaterSurface(coordinates, options = {}) {// 创建水面材质const waterMaterial = createWaterMaterial();// 应用选项if (options.waveStrength !== undefined) waterMaterial.uniforms.waveStrength = options.waveStrength;if (options.waveSpeed !== undefined) waterMaterial.uniforms.waveSpeed = options.waveSpeed;if (options.reflectivity !== undefined) waterMaterial.uniforms.reflectivity = options.reflectivity;if (options.waterColor !== undefined) waterMaterial.uniforms.waterColor = options.waterColor;// 创建水面实体const water = viewer.entities.add({rectangle: {coordinates: Cesium.Rectangle.fromDegrees(coordinates[0], coordinates[1], coordinates[2], coordinates[3]),material: waterMaterial,height: options.height || 0}});// 更新时间viewer.scene.preRender.addEventListener((scene, time) => {waterMaterial.uniforms.time = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);});return {entity: water,material: waterMaterial};
}// 创建湖泊
const lake = createWaterSurface([116.35, 39.85, 116.45, 39.95],{waveStrength: 0.1,waveSpeed: 0.03,reflectivity: 0.7,waterColor: new Cesium.Color(0.0, 0.4, 0.6, 1.0),height: 5 // 水面高度}
);

📝 自定义材质开发指南

1. 开发自定义材质的步骤

  1. 规划材质功能

    • 确定材质的视觉效果
    • 确定需要哪些可调参数
    • 是否需要动画效果
  2. 准备所需资源

    • 纹理图像
    • 法线贴图
    • 噪声图等
  3. 定义材质参数

    • 在uniforms中定义参数
    • 设置默认值和取值范围
  4. 编写GLSL着色器代码

    • 实现czm_getMaterial函数
    • 处理纹理坐标和采样
    • 计算颜色和透明度
  5. 测试与调试

    • 预览材质效果
    • 调整参数和代码
    • 优化性能

2. 性能优化建议

  1. 着色器代码优化

    • 减少条件分支
    • 避免复杂数学运算
    • 使用内置函数替代自定义实现
  2. 纹理使用优化

    • 使用适当尺寸的纹理
    • 采用mipmap减少采样伪影
    • 合理设置采样次数
  3. 动态更新优化

    • 避免每帧都创建新的材质实例
    • 只更新必要的uniform值
    • 考虑使用回调函数缓存结果

🏆 自定义材质最佳实践

  1. 模块化设计

    • 将复杂材质拆分为可重用组件
    • 创建材质工厂或管理器
    • 实现参数接口方便修改
  2. 结合其他Cesium功能

    • 与实体属性结合
    • 配合相机事件实现交互
    • 与时钟控制同步动画
  3. 调试与维护

    • 添加调试界面实时调整参数
    • 记录材质创建和使用情况
    • 在不同设备上测试兼容性
http://www.xdnf.cn/news/263953.html

相关文章:

  • 硬件工程师面试常见问题(12)
  • 【LeetCode Hot100】贪心篇
  • 在pycharm profession 2020.3将.py程序使用pyinstaller打包成exe
  • Windows 中使用dockers创建指定java web 为镜像和运行容器
  • C++ STL vector高级特性与实战技巧
  • AVFormatContext 再分析零
  • 在Windows系统中使用Docker发布镜像到镜像仓库
  • 用PyTorch搭建卷积神经网络实现MNIST手写数字识别
  • 生成式 AI 的工作原理
  • Elasticsearch 中的索引模板:如何使用可组合模板
  • 【在Spring Boot中集成Redis】
  • 【赵渝强老师】TiDB生态圈组件
  • 3D人物关系图开发实战:Three.js实现自动旋转可视化图谱(附完整代码)
  • 人工智能助力工业制造:迈向智能制造的未来
  • 别样健康养生之道
  • AI 与生物技术的融合:开启精准医疗的新纪元
  • ros2 humble 控制真实机械臂(以lerobot为例)
  • 一种基于重建前检测的实孔径雷达实时角超分辨方法——论文阅读
  • **Java面试大冒险:谢飞机的幽默与技术碰撞记**
  • 做响应式布局网页多简单
  • AI生成视频检测方法及其相关研究
  • WebRTC 服务器之Janus概述和环境搭建
  • Spring MVC入门
  • 第12章:精神力的禁忌边界
  • 强化学习--3.值函数的方法(贝尔曼方程)
  • 直播推流拉流Token验证流程(直播服务器:SRS,验证服务器:EGGS(nodejs))
  • 智能决策支持系统的系统结构:四库架构与融合范式
  • k8s笔记——kubebuilder工作流程
  • 嵌入式硬件篇---STM32F103C8T6STM32F103RCT6
  • Flink 的状态机制