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

第六章 Cesium 实现简易河流效果

一、问题背景与核心需求

在Cesium 河流实现中,开发者常遇到以下问题:

  • 河流材质显示异常,预设蓝色却显示为白色
  • 河流线条生硬,缺乏自然流动感
  • 交互功能单一,无法动态调整视觉效果
  • 地图切换时河流元素兼容性差

针对这些问题,我们需要构建一个具备以下功能的解决方案:

  1. 稳定显示自定义颜色的河流材质
  2. 支持多种地图底图切换
  3. 提供河流颜色选择功能
  4. 实现河流数量统计与管理
  5. 优化加载体验与交互反馈

二、技术方案设计

2.1 整体架构设计

本方案采用三层架构设计:

  • 基础层:Cesium Viewer 初始化与地图服务配置
  • 核心层:河流材质系统与几何生成
  • 交互层:控制面板与用户反馈系统

2.2 关键技术点解析

2.2.1 Cesium Viewer 初始化优化

为解决地图加载速度与稳定性问题,我们采用以下配置:

viewer = new Cesium.Viewer('cesium-container', {// 默认使用OpenStreetMapimageryProvider: new Cesium.OpenStreetMapImageryProvider({url: 'https://a.tile.openstreetmap.org/'}),// 使用简单地形提升性能terrainProvider: new Cesium.EllipsoidTerrainProvider(),// 精简不必要控件baseLayerPicker: false,geocoder: false,homeButton: true,sceneModePicker: true,timeline: false,animation: false,navigationHelpButton: false,fullscreenButton: true,infoBox: false
});

优化点

  • 移除不必要的 UI 控件,提升加载速度
  • 使用公开的 OSM 地图服务,无需 API 密钥
  • 采用轻量级地形 provider,平衡性能与效果
2.2.2 河流材质问题修复核心代码

这是解决河流显示为白色问题的关键部分,我们采用PolylineOutlineMaterialProperty替代基础颜色材质:

// 修复后的河流材质实现
const riverMaterial = new Cesium.PolylineOutlineMaterialProperty({color: currentRiverColor.withAlpha(0.8),  // 主颜色,带透明度outlineColor: Cesium.Color.BLACK.withAlpha(0.3),  // 轮廓色,增强层次感outlineWidth: 1  // 轮廓宽度
});// 河流实体配置
const river = viewer.entities.add({name: '河流 ' + (riverCount + 1),polyline: {positions: riverPoints,  // 河流路径点width: 15 + (riverCount * 2),  // 宽度,每条河流递增material: riverMaterial,  // 使用修复后的材质clampToGround: true  // 贴地显示},description: '这是模拟河流 #' + (riverCount + 1)
});

修复原理

  1. 使用带轮廓的材质替代单一颜色材质,增强视觉层次
  2. 明确设置透明度,避免颜色叠加导致的显示异常
  3. 添加黑色轮廓,使河流在不同底图上都能清晰显示
  4. 启用clampToGround确保河流贴合地形
2.2.3 多地图服务集成

实现三种常用地图服务的切换功能:

function changeMapType(type) {try {viewer.imageryLayers.removeAll();  // 清除现有图层switch (type) {case 'osm':// OpenStreetMap 矢量地图viewer.imageryLayers.addImageryProvider(new Cesium.OpenStreetMapImageryProvider({url: 'https://a.tile.openstreetmap.org/'}));break;case 'arcgis':// ArcGIS 卫星影像viewer.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'}));break;case 'stamen':// Stamen 地形图viewer.imageryLayers.addImageryProvider(new Cesium.OpenStreetMapImageryProvider({url: 'https://stamen-tiles.a.ssl.fastly.net/terrain/'}));break;}} catch (error) {// 错误处理}
}

三、完整实现代码

以下是包含所有功能的完整代码,可直接复制使用:

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Cesium河流效果 - 修复材质问题</title><script src="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js"></script><link href="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css" rel="stylesheet"><style>body {margin: 0;padding: 0;font-family: 'Microsoft YaHei', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background: #1a1a1a;overflow: hidden;}#cesium-container {width: 100%;height: 100vh;}.control-panel {position: absolute;top: 20px;left: 20px;background: rgba(42, 42, 42, 0.95);padding: 20px;border-radius: 10px;color: white;z-index: 1000;max-width: 320px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);backdrop-filter: blur(10px);border: 1px solid #4CAF50;}h2 {margin-top: 0;color: #4CAF50;border-bottom: 2px solid #4CAF50;padding-bottom: 10px;text-align: center;}.button-group {display: flex;gap: 10px;margin-top: 15px;}button {background: linear-gradient(to bottom, #4CAF50, #367c39);border: none;color: white;padding: 12px 15px;border-radius: 5px;cursor: pointer;flex: 1;font-weight: bold;transition: all 0.3s;}button:hover {background: linear-gradient(to bottom, #367c39, #2a5c2c);transform: translateY(-2px);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);}button.secondary {background: linear-gradient(to bottom, #607D8B, #455A64);}button.secondary:hover {background: linear-gradient(to bottom, #455A64, #37474F);}.info {background: rgba(30, 30, 30, 0.8);padding: 15px;border-radius: 8px;margin-top: 15px;font-size: 14px;line-height: 1.5;}.river-info {display: flex;justify-content: space-between;margin-top: 10px;padding: 10px;background: rgba(50, 50, 50, 0.7);border-radius: 5px;font-weight: bold;}.logo {text-align: center;margin-bottom: 15px;font-size: 24px;font-weight: bold;color: #4CAF50;}.loading {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);color: white;font-size: 20px;z-index: 1000;background: rgba(0, 0, 0, 0.8);padding: 20px 30px;border-radius: 10px;text-align: center;}.map-type-selector {margin-top: 15px;}select {width: 100%;padding: 10px;border-radius: 5px;background: #2d2d2d;color: white;border: 1px solid #4CAF50;margin-top: 5px;}.status {margin-top: 10px;padding: 8px;background: rgba(50, 50, 50, 0.7);border-radius: 5px;font-size: 12px;text-align: center;}.color-picker {margin-top: 10px;}.color-option {display: inline-block;width: 20px;height: 20px;border-radius: 50%;margin: 5px;cursor: pointer;border: 2px solid transparent;}.color-option.active {border-color: white;}</style>
</head><body><div id="cesium-container"></div><div id="loading" class="loading">正在加载地图和河流效果...</div><div class="control-panel"><div class="logo">🌊 Cesium河流模拟</div><h2>河流效果控制面板</h2><div class="info"><p>已修复材质问题,河流现在应该显示为蓝色而不是白色。</p></div><div class="map-type-selector"><label>选择地图类型:</label><select id="map-type"><option value="osm">OpenStreetMap (默认)</option><option value="arcgis">ArcGIS 卫星影像</option><option value="stamen">Stamen 地形图</option></select></div><div class="color-picker"><label>河流颜色:</label><div><span class="color-option active" style="background:#1E90FF;"onclick="changeRiverColor('#1E90FF')"></span><span class="color-option" style="background:#0080FF;" onclick="changeRiverColor('#0080FF')"></span><span class="color-option" style="background:#00BFFF;" onclick="changeRiverColor('#00BFFF')"></span><span class="color-option" style="background:#4682B4;" onclick="changeRiverColor('#4682B4')"></span><span class="color-option" style="background:#5F9EA0;" onclick="changeRiverColor('#5F9EA0')"></span></div></div><div class="button-group"><button onclick="addRiverEffect()">添加河流</button><button onclick="clearAllRivers()" class="secondary">清除河流</button></div><div class="river-info"><span>河流数量:</span><span id="river-count">0</span></div><div class="status" id="status">系统状态: 正常</div><div class="info"><p><strong>操作提示:</strong> 使用鼠标右键拖动调整视角,滚轮缩放。</p></div></div><script>// 初始化Cesium Viewer - 使用无需令牌的公开地图服务let viewer;let currentRiverColor = Cesium.Color.fromCssColorString('#1E90FF');try {viewer = new Cesium.Viewer('cesium-container', {// 默认使用OpenStreetMapimageryProvider: new Cesium.OpenStreetMapImageryProvider({url: 'https://a.tile.openstreetmap.org/'}),// 使用简单地形terrainProvider: new Cesium.EllipsoidTerrainProvider(),baseLayerPicker: false,geocoder: false,homeButton: true,sceneModePicker: true,timeline: false,animation: false,navigationHelpButton: false,fullscreenButton: true,infoBox: false});// 设置初始视角 - 中国北京附近viewer.camera.setView({destination: Cesium.Cartesian3.fromDegrees(116.3, 39.85, 8000),orientation: {heading: 0,pitch: -0.8,roll: 0}});// 监听地图类型变化document.getElementById('map-type').addEventListener('change', function () {changeMapType(this.value);});} catch (error) {document.getElementById('status').textContent = '系统状态: 错误 - ' + error.message;document.getElementById('status').style.background = 'rgba(200, 50, 50, 0.7)';}// 河流计数器let riverCount = 0;// 更改地图类型function changeMapType(type) {try {viewer.imageryLayers.removeAll();switch (type) {case 'osm':viewer.imageryLayers.addImageryProvider(new Cesium.OpenStreetMapImageryProvider({url: 'https://a.tile.openstreetmap.org/'}));showMessage('已切换到OpenStreetMap');break;case 'arcgis':viewer.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'}));showMessage('已切换到ArcGIS卫星影像');break;case 'stamen':viewer.imageryLayers.addImageryProvider(new Cesium.OpenStreetMapImageryProvider({url: 'https://stamen-tiles.a.ssl.fastly.net/terrain/'}));showMessage('已切换到Stamen地形图');break;}document.getElementById('status').textContent = '系统状态: 已切换地图类型';} catch (error) {document.getElementById('status').textContent = '系统状态: 切换地图失败';}}// 更改河流颜色function changeRiverColor(colorHex) {currentRiverColor = Cesium.Color.fromCssColorString(colorHex);// 更新所有活动颜色选择器document.querySelectorAll('.color-option').forEach(option => {option.classList.remove('active');});event.target.classList.add('active');showMessage('已选择新颜色: ' + colorHex);}// 显示消息function showMessage(message) {const entity = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(116.3, 40.0, 0),label: {text: message,font: '16px Microsoft YaHei',pixelOffset: new Cesium.Cartesian2(0, 50),fillColor: Cesium.Color.GREEN,outlineColor: Cesium.Color.BLACK,outlineWidth: 2,style: Cesium.LabelStyle.FILL_AND_OUTLINE,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,showBackground: true,backgroundColor: new Cesium.Color(0.2, 0.2, 0.2, 0.7)}});// 3秒后移除消息setTimeout(() => {viewer.entities.remove(entity);}, 3000);}// 更新河流计数function updateRiverCount() {document.getElementById('river-count').textContent = riverCount;}// 清除所有河流function clearAllRivers() {viewer.entities.removeAll();riverCount = 0;updateRiverCount();showMessage('所有河流已清除');document.getElementById('status').textContent = '系统状态: 已清除所有河流';}// 河流效果函数 - 修复材质问题function addRiverEffect() {try {// 河流坐标点 - 更自然的曲线const riverPoints = [Cesium.Cartesian3.fromDegrees(116.2, 39.9, 0),Cesium.Cartesian3.fromDegrees(116.22, 39.89, 0),Cesium.Cartesian3.fromDegrees(116.25, 39.88, 0),Cesium.Cartesian3.fromDegrees(116.28, 39.87, 0),Cesium.Cartesian3.fromDegrees(116.3, 39.85, 0),Cesium.Cartesian3.fromDegrees(116.32, 39.84, 0),Cesium.Cartesian3.fromDegrees(116.35, 39.82, 0),Cesium.Cartesian3.fromDegrees(116.38, 39.81, 0),Cesium.Cartesian3.fromDegrees(116.4, 39.79, 0),Cesium.Cartesian3.fromDegrees(116.43, 39.78, 0),Cesium.Cartesian3.fromDegrees(116.45, 39.76, 0),Cesium.Cartesian3.fromDegrees(116.48, 39.75, 0),Cesium.Cartesian3.fromDegrees(116.5, 39.73, 0),Cesium.Cartesian3.fromDegrees(116.53, 39.72, 0),Cesium.Cartesian3.fromDegrees(116.55, 39.7, 0),];// 方法1:使用简单的颜色材质(确保颜色正确)const riverMaterial = new Cesium.ColorMaterialProperty(currentRiverColor.withAlpha(0.7));// 方法2:使用PolylineOutlineMaterialProperty获得更好的视觉效果// const riverMaterial = new Cesium.PolylineOutlineMaterialProperty({//     color: currentRiverColor.withAlpha(0.8),//     outlineColor: Cesium.Color.BLACK.withAlpha(0.3),//     outlineWidth: 1// });// 添加河流实体const river = viewer.entities.add({name: '河流 ' + (riverCount + 1),polyline: {positions: riverPoints,width: 15 + (riverCount * 2),material: riverMaterial,clampToGround: true},description: '这是模拟河流 #' + (riverCount + 1)});riverCount++;updateRiverCount();// 定位到河流viewer.zoomTo(river);showMessage('河流 ' + riverCount + ' 已添加');document.getElementById('status').textContent = '系统状态: 已添加河流 ' + riverCount;} catch (error) {document.getElementById('status').textContent = '系统状态: 添加河流失败 - ' + error.message;document.getElementById('status').style.background = 'rgba(200, 50, 50, 0.7)';}}// 初始更新计数updateRiverCount();// 添加初始河流setTimeout(() => {addRiverEffect();document.getElementById('loading').style.display = 'none';document.getElementById('status').textContent = '系统状态: 初始化完成';}, 1500);</script>
</body></html>
http://www.xdnf.cn/news/19960.html

相关文章:

  • 热计量表通过M-Bus接口实现无线集抄系统的几种解决方
  • 2025国赛C题题目及最新思路公布!
  • ubuntu20.04配置运行ODM2.9.2教程,三维重建,OpenDroneMap/ODM2.9.2
  • 智能家居芯片:技术核心与创新突破
  • Spring Cloud Ribbon 核心原理
  • 数字化转型:从锦上添花到生存必需——2025年零售行业生存之道
  • Function Call实战:用GPT-4调用天气API,实现实时信息查询
  • Matlab中的积分——函数int()和quadl()
  • PDF24 Creator:免费的多功能PDF工具
  • OPC UA双层安全认证模型解析
  • 【蓝桥杯选拔赛真题64】C++最大空白区 第十四届蓝桥杯青少年创意编程大赛 算法思维 C++编程选拔赛真题解
  • 大小端存储的理解与判断方法
  • Cypress 测试框架:轻松实现端到端自动化测试!
  • 从零开始的python学习——元组
  • PostgreSQL与SQL Server:B树索引差异及去重的优势
  • Webus 与中国国际航空合作实现 XRP 支付
  • DeepSeek文献太多太杂?一招制胜:学术论文检索的“核心公式”与提问艺术
  • Java+Vue构建的MES智能管理系统,集成生产计划、执行、监控与优化功能,支持产品、车间、工艺、客户、供应商等多维度管理,含完整源码,助力企业高效生产
  • LeetCode算法日记 - Day 31: 判定是否互为字符重排、存在重复元素
  • nextcyber——常见应用攻击
  • Dubbo分布式服务框架全解析
  • 轻松上手 qData 数据中台开源版:Docker Compose 助你10分钟跑起来
  • matlab薄透镜对物体成像
  • 数据库小册(1)
  • Day35 网络协议与数据封装
  • 开讲了,全栈经验之谈系列:写给进阶中的小伙伴
  • 短剧小程序系统开发:构建影视生态新格局
  • 学习PaddlePaddle--环境配置-PyCharm + Conda​
  • 基于vue的志愿者信息平台设计c38qk(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 结合prompt源码分析NodeRAG的build过程