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

第六章 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.dtcms.com/a/367209.html

相关文章:

  • FastDDS:第三节(3.2小节)
  • 规则引擎开发现在已经演化成算法引擎了
  • #T1359. 围成面积
  • Java并发编程:sleep()与wait()核心区别详解
  • 通过Interface扫描获取所有其实现类
  • AI 浪潮下阿里云“高光”乍现,但离终局胜利尚远
  • MySQL主从复制进阶(GTID复制,半同步复制)
  • 搭建基于 Solon AI 的 Streamable MCP 服务并部署至阿里云百炼
  • 鸿蒙NEXT动画开发指南:组件与页面典型动画场景解析
  • ios按键精灵提示 “设备信息丢失”如何处理?
  • 在Ant Design Vue 中使用图片预览的插件
  • Elixir通过Onvif协议控制IP摄像机,扩展ExOnvif的摄像头停止移动 Stop 功能
  • 【RNN-LSTM-GRU】第五篇 序列模型实战指南:从选型到优化与前沿探索
  • 对于数据结构:链表的超详细保姆级解析
  • 从0到1搭建某铝箔智慧工厂网络:5G与WiFi 6助力智能制造
  • 2025年财会领域专业资格认证选择指南
  • AR眼镜在智能制造的应用方向和场景用例|阿法龙XR云平台
  • BERT家族进化史:从BERT到LLaMA,每一次飞跃都源于对“学习”的更深理解
  • 【深度学习】P1 引言:深度学习的万家灯火
  • 网络安全初级-渗透测试
  • 下载apache-maven-3.6.1版本并配置maven镜像及本地仓库[超简单]
  • Hunyuan-MT-7B模型介绍
  • 告别低效广告!亚马逊关键词筛选全流程攻略
  • matlab版本粒子群算法(PSO)在路径规划中的应用
  • ultralytics/nn/tasks.py源码学习笔记——核心函数parse_model
  • 【正整数的最优分解2的次方和形式非0次方】2022-11-1
  • Java基础知识点汇总(五)
  • 什么是压力测试,有哪些方法
  • AI入坑: Trae 通过http调用.net 开发的 mcp server
  • IIS服务器下做浏览器缓存