Appearance
ViewShedEffect 可视域分析
以观察点为虚拟相机建立分析式阴影贴图,对整帧做「深度重建 → 变换进虚拟相机空间 → 阴影图遮挡判定」的后处理染色:可视区染
visibleAreaColor(默认绿)、不可视区染invisibleAreaColor(默认红)。遮挡随地形 / 3D Tiles 起伏实时变化,用于哨位通视、雷达遮蔽、反恐布控等「从某点能看到哪些区域」的分析场景。
能力定位
ViewShedEffect 适合:
- 通视分析:从观测点判定可见/不可见区域;
- 雷达/哨位遮挡:评估地形或建筑对视线的遮蔽;
- 态势叠加:与 3D Tiles 倾斜摄影结合,在真实城市模型上做可视域推演。
与 RadarSweepEffect(屏幕空间后处理)同属 PostProcessStage 一族,可叠加共存;但可视域需要真实的遮挡判定,因此额外引入了分析式阴影贴图,作用于整帧而非局部扫描线。
构造函数
ts
constructor(options: ViewShedEffectOptions)ts
interface ViewShedEffectOptions {
viewPosition: Cartesian3 // 观测点位置(必填,世界坐标)
viewPositionEnd: Cartesian3 // 目标点位置(必填,与观测点不同)
viewDistance?: number // 可视距离(米),默认 1000
viewHeading?: number // 航向角(度),默认 0
viewPitch?: number // 俯仰角(度),默认 0
horizontalViewAngle?: number // 水平视场角(度),默认 90
verticalViewAngle?: number // 垂直视场角(度),默认 60
visibleAreaColor?: Color // 可视区域颜色,默认 Color.LIME
invisibleAreaColor?: Color // 不可视区域颜色,默认 Color.RED
}| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
viewPosition | Cartesian3 | — | 观测点位置(世界坐标),必填,缺省抛错 |
viewPositionEnd | Cartesian3 | — | 目标点位置(世界坐标),必填且须与观测点不同 |
viewDistance | number | 1000 | 可视距离(米),须大于 0 |
viewHeading | number | 0 | 航向角(度)。默认 0,对齐源案例 ViewShedStage;由两点方位推导的写法见下方进阶示例 |
viewPitch | number | 0 | 俯仰角(度),默认 0,同上 |
horizontalViewAngle | number | 90 | 水平视场角(度),须在 (0, 360) |
verticalViewAngle | number | 60 | 垂直视场角(度),须在 (0, 180) |
visibleAreaColor | Color | Color.LIME | 可视区域染色 |
invisibleAreaColor | Color | Color.RED | 不可视区域染色 |
viewHeading/viewPitch默认 0(对齐源案例构造参数默认值)。源案例的交互层(ViewShedDraw+CameraLine)在两点拾取后通过getHeading/getPitch推导航向与俯仰,这一推导不属于核心类职责,应在调用方完成(见进阶示例)。
生命周期
实现 Lifecycle<Viewer> 契约,on/off/destroy 均幂等:
ts
on(viewer: Viewer): void // 创建虚拟相机 + 分析式 ShadowMap + 后处理 stage + 视锥边线/草图实体
off(viewer: Viewer): void // 移除 stage 与实体,并还原 on 之前的 scene.shadowMap
destroy(viewer: Viewer): void // 等价于 off相比源案例 clear() 未还原 scene.shadowMap(会污染场景阴影),off/destroy 会无条件还原 on 之前的阴影贴图配置。
基础示例
ts
import { ViewShedEffect } from '@nexa/gis-cesium'
import { Cartesian3 } from 'cesium'
const effect = new ViewShedEffect({
viewPosition: Cartesian3.fromDegrees(117.079958, 31.657521, 60),
viewPositionEnd: Cartesian3.fromDegrees(117.084658, 31.654321, 8),
viewDistance: 500,
horizontalViewAngle: 90,
verticalViewAngle: 60,
})
effect.on(viewer)进阶示例
两点交互 + 方位推导(对齐源案例 ViewShedDraw/CameraLine/Utils):先拾取观测点,再拾取目标点,用 getHeading/getPitch 推导航向/俯仰,用两点距离作为可视距离。
ts
import { ViewShedEffect } from '@nexa/gis-cesium'
import { Cartesian3, Math as CesiumMath, Matrix4, Transforms } from 'cesium'
// 方位推导(对齐源案例 Utils/getHeading、getPitch)
function getHeading (from: Cartesian3, to: Cartesian3): number {
const final = new Cartesian3()
const m = Transforms.eastNorthUpToFixedFrame(from)
Matrix4.inverse(m, m)
Matrix4.multiplyByPoint(m, to, final)
Cartesian3.normalize(final, final)
return CesiumMath.toDegrees(Math.atan2(final.x, final.y))
}
function getPitch (from: Cartesian3, to: Cartesian3): number {
const final = new Cartesian3()
const m = Transforms.eastNorthUpToFixedFrame(from)
Matrix4.inverse(m, m)
Matrix4.multiplyByPoint(m, to, final)
Cartesian3.normalize(final, final)
return CesiumMath.toDegrees(Math.asin(final.z))
}
// 交互:首点 = 观测点,次点 = 目标点
let first: Cartesian3 | undefined
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((e) => {
const position = viewer.scene.pickPosition(e.position)
if (!position) return
if (!first) {
first = position
} else {
const effect = new ViewShedEffect({
viewPosition: first,
viewPositionEnd: position,
viewDistance: Cartesian3.distance(first, position),
viewHeading: getHeading(first, position),
viewPitch: getPitch(first, position),
})
effect.on(viewer)
first = undefined
}
}, ScreenSpaceEventType.LEFT_CLICK)实现说明
- 分析式阴影贴图:
new ShadowMap({ fromLightSource: false, isPointLight: true, pointLightRadius, cascadesEnabled: false, size, softShadows, normalOffset: false })以虚拟相机为光源,注入viewer.scene.shadowMap。fromLightSource:false保证其不参与场景光照,仅作遮挡判定用(对齐源案例createShadowMap); - 屏幕空间后处理:PostProcessStage 片元着色器对每个像素做
depthTexture 解包 → czm_inverseProjection 反投影重建视空间坐标 → czm_inverseView 转世界坐标 → camera_view_matrix 变换进虚拟相机空间,落在视锥内再czm_shadowVisibility判定遮挡,可视/不可视分别 mix 染色; - GLSL 3.00 迁移:源着色器(Cesium 1.72)按 1.133 语法迁移 ——
varying → in、gl_FragColor → out_FragColor、texture2D → texture;自定义czm_shadowVisibility(samplerCube, zx_shadowParameters)与引擎内置同名函数(czm_shadowParameters结构体)构成重载,编译期可区分; - 深度重建 builtins:
czm_inverseProjection/czm_unpackDepth/czm_reverseLogDepth/czm_depthRange/czm_inverseView/czm_inverseViewRotation均在 1.133 引擎后处理管线中提供; - 私有 API 使用:
scene.context(@privategetter)、scene._frameState、shadowMap._shadowMapTexture/_shadowMapMatrix/_lightPositionEC/_distance/_pointBias/_textureSize均经Reflect.get读取,已在 1.133 引擎逐一核验存在(见 Gate 1 风险 R3,需浏览器实测编译); - 资源所有权:本效果创建的 stage、视锥边线/草图实体由
off/destroy移除,且还原scene.shadowMap。
清理责任
ts
effect.destroy(viewer) // 或 effect.off(viewer),等价且幂等重复调用 destroy/off 安全。
Cesium 版本限制
- 依赖
ShadowMap(分析式)、PostProcessStage、Camera、scene.context与_frameState等私有/半私有能力; - 着色器为 GLSL 3.00,依赖 1.133 后处理编译管线;
- 已验证目标版本:Cesium 1.133.1。