Cesium实战:从平面到立体,手把手教你绘制10种常见几何图形(附完整代码)
在三维地理信息可视化领域,Cesium凭借其强大的图形渲染能力成为开发者首选工具。本文将带您系统掌握从基础平面图形到复杂立体模型的完整绘制方法,通过参数解析和实战代码演示,帮助您快速构建专业级三维地理可视化应用。
1. 环境准备与基础概念
1.1 初始化Cesium场景
开始绘制前需要搭建基础环境。创建HTML文件并引入Cesium库:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <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"> </head> <body> <div id="cesiumContainer"></div> <script> const viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrain() }); viewer.scene.globe.depthTestAgainstTerrain = true; </script> </body> </html>关键配置说明:
createWorldTerrain()启用全球地形数据depthTestAgainstTerrain确保图形与地形正确交互
1.2 坐标系与单位系统
Cesium使用两种主要坐标系:
- WGS84经纬度:
fromDegrees(longitude, latitude, height) - 笛卡尔空间坐标:
Cartesian3(x, y, z)
长度单位默认为米,角度使用弧度制。常用转换方法:
// 度转弧度 Cesium.Math.toRadians(45) // 弧度转度 Cesium.Math.toDegrees(Math.PI/4)2. 基础平面图形绘制
2.1 矩形与正方形
矩形是最基础的图形元素,通过指定对角坐标定义范围:
const rectangle = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( 116.3, 39.9, // 西南角 116.5, 40.1 // 东北角 ), material: new Cesium.StripeMaterialProperty({ evenColor: Cesium.Color.WHITE, oddColor: Cesium.Color.BLUE, repeat: 10 }), outline: true, outlineColor: Cesium.Color.BLACK } });参数进阶:
stRotation纹理旋转角度(弧度)rotation整个矩形旋转角度classificationType设置与地形的交互方式
2.2 多边形与复杂形状
多边形通过顶点序列定义,支持孔洞嵌套:
const polygonWithHole = viewer.entities.add({ polygon: { hierarchy: { positions: Cesium.Cartesian3.fromDegreesArray([ -75.0, 35.0, -75.0, 40.0, -80.0, 40.0, -80.0, 35.0 ]), holes: [{ positions: Cesium.Cartesian3.fromDegreesArray([ -77.0, 36.0, -77.0, 39.0, -78.0, 39.0, -78.0, 36.0 ]) }] }, material: Cesium.Color.GREEN.withAlpha(0.5), extrudedHeight: 100000 // 初步立体化 } });2.3 圆形与椭圆
椭圆通过长短轴定义,圆形是长短轴相等的特例:
const ellipse = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-95.0, 40.0), ellipse: { semiMinorAxis: 150000.0, semiMajorAxis: 300000.0, rotation: Cesium.Math.toRadians(30), material: new Cesium.GridMaterialProperty({ color: Cesium.Color.YELLOW, cellAlpha: 0.2, lineCount: new Cesium.Cartesian2(8, 8), lineThickness: new Cesium.Cartesian2(2.0, 2.0) }) } });3. 2D到3D的立体化转换
3.1 高度拉伸原理
Cesium通过三个关键参数实现立体化:
height:基准高度(相对椭球面)extrudedHeight:拉伸高度closeTop/bottom:是否封闭顶底面
const extrudedPolygon = viewer.entities.add({ polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray([ -70.0, 30.0, -72.0, 32.0, -68.0, 33.0 ]), height: 50000, // 离地高度 extrudedHeight: 200000, // 总高度 material: Cesium.Color.RED.withAlpha(0.7), outline: true, closeTop: false // 开放顶部 } });3.2 参数组合效果对比
下表展示不同参数组合的视觉效果:
| 参数组合 | 效果描述 | 典型应用 |
|---|---|---|
| 仅height | 平面抬升 | 悬浮标识 |
| height+extrudedHeight | 完整立体 | 建筑体块 |
| height+extrudedHeight+closeTop=false | 空心柱体 | 围栏立柱 |
| 仅extrudedHeight | 从地面拉伸 | 地形突出物 |
3.3 纹理与光照优化
立体图形的视觉效果可通过材质增强:
const texturedBuilding = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees(-122.4, 37.8, -122.3, 37.9), extrudedHeight: 200000, material: new Cesium.ImageMaterialProperty({ image: 'textures/brick.jpg', repeat: new Cesium.Cartesian2(4, 4) }), shadows: Cesium.ShadowMode.ENABLED } });4. 进阶立体图形绘制
4.1 参数化几何体
Cesium提供多种参数化几何体类型:
// 圆柱体 const cylinder = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-105.0, 35.0, 100000), cylinder: { length: 300000.0, topRadius: 50000.0, bottomRadius: 100000.0, material: Cesium.Color.CYAN.withAlpha(0.8), slices: 64 // 侧面细分程度 } }); // 椭球体 const ellipsoid = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0), ellipsoid: { radii: new Cesium.Cartesian3(150000.0, 100000.0, 50000.0), material: new Cesium.CheckerboardMaterialProperty() } });4.2 组合图形与动画
通过实体组合和属性回调实现动态效果:
// 旋转的锥体 const rotatingCone = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-110.0, 35.0), cylinder: { length: 400000.0, topRadius: 0.0, bottomRadius: 150000.0, material: Cesium.Color.ORANGE, rotation: new Cesium.CallbackProperty(function(time) { return Cesium.Math.toRadians(Cesium.JulianDate.now(time).secondsOfDay * 10); }, false) } });4.3 高级几何构造
使用PolylineVolume创建复杂路径立体图形:
// 星形截面管道 const starTube = viewer.entities.add({ polylineVolume: { positions: Cesium.Cartesian3.fromDegreesArrayHeights([ -115.0, 35.0, 0, -117.0, 37.0, 200000, -120.0, 35.0, 0 ]), shape: computeStarShape(5, 50000, 30000), material: Cesium.Color.PURPLE } }); function computeStarShape(arms, outerRadius, innerRadius) { const positions = []; for (let i = 0; i <= arms*2; i++) { const angle = Math.PI * i / arms; const radius = i % 2 === 0 ? outerRadius : innerRadius; positions.push(new Cesium.Cartesian2( Math.cos(angle) * radius, Math.sin(angle) * radius )); } return positions; }5. 性能优化与实战技巧
5.1 批量绘制与实例化
大量图形绘制时应使用Primitive API:
const instances = []; for (let i = 0; i < 100; i++) { instances.push(new Cesium.GeometryInstance({ geometry: new Cesium.RectangleGeometry({ rectangle: Cesium.Rectangle.fromDegrees( -180 + Math.random() * 360, -90 + Math.random() * 180, -180 + Math.random() * 360, -90 + Math.random() * 180 ), vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT }), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.fromRandom({ alpha: 0.5 }) ) } })); } viewer.scene.primitives.add(new Cesium.Primitive({ geometryInstances: instances, appearance: new Cesium.EllipsoidSurfaceAppearance({ material: new Cesium.Material({ fabric: { type: 'Color', uniforms: { color: new Cesium.Color(1.0, 1.0, 1.0, 0.5) } } }) }) }));5.2 LOD与可见性控制
const lodEntity = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees(-70, 30, -60, 40), material: Cesium.Color.BLUE, show: new Cesium.CallbackProperty(function() { return viewer.camera.positionCartographic.height < 10000000; }, false) } });5.3 交互与拾取优化
viewer.screenSpaceEventHandler.setInputAction(function(movement) { const picked = viewer.scene.pick(movement.endPosition); if (Cesium.defined(picked) && picked.id) { picked.id.color = Cesium.Color.YELLOW; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);6. 典型应用场景实现
6.1 三维建筑可视化
// 建筑群生成 const buildingHeights = [50, 80, 120, 200, 150]; buildingHeights.forEach((height, index) => { viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees( 116.3 + index * 0.02, 39.9, 116.3 + (index + 1) * 0.02, 40.0 ), extrudedHeight: height, material: new Cesium.ColorMaterialProperty( Cesium.Color.fromCssColorString('#7FDBFF') .withAlpha(0.7) ), shadows: Cesium.ShadowMode.ENABLED } }); });6.2 地形剖面分析
const profilePositions = Cesium.Cartesian3.fromDegreesArray([ 116.3, 39.9, 116.5, 39.9, 116.5, 40.1, 116.3, 40.1 ]); const profileWall = viewer.entities.add({ wall: { positions: profilePositions, maximumHeights: [100000, 200000, 150000, 80000], material: new Cesium.StripeMaterialProperty({ evenColor: Cesium.Color.WHITE.withAlpha(0.5), oddColor: Cesium.Color.BLUE.withAlpha(0.5) }) } });6.3 动态路径可视化
const path = []; for (let i = 0; i < 10; i++) { path.push(Cesium.Cartesian3.fromDegrees( -100 + Math.random() * 20, 30 + Math.random() * 10, Math.random() * 100000 )); } const dynamicPath = viewer.entities.add({ polylineVolume: { positions: path, shape: computeCircle(10000), material: new Cesium.PolylineGlowMaterialProperty({ glowPower: 0.2, color: Cesium.Color.RED }), cornerType: Cesium.CornerType.ROUND } });