【Cesium】在着色器中计算片元的高程

问题提出

有时候在 Cesium 上做一些效果时,需要知道片元的高程。而渲染是基于笛卡尔坐标的,没有高程这个概念。怎么在着色器中计算片元的高程呢?

基本思路

通常做法是在着色器里对深度纹理采样,将片元的深度值转换为相机坐标。然后把相机坐标转换为世界坐标,世界坐标是片元相对于地球椭球中心的偏移量,下图中假设片元的世界坐标为 (x, y, z)。用世界坐标的模减去片元对应的椭球半径就可以得到高程。但是逐片元去计算它们对应的椭球半径在着色器里不好实现,在CPU中计算相机位置处的椭球半径(下图中的 earthRadius )来近似地作为相机观察范围内所有片元对应的椭球半径从性能和实现难度上都是更优解。

图1 计算片元高程基本思路

具体步骤

1、在CPU中计算相机所在位置对应的地球半径,作为 uniform 变量传入着色器中:相机世界坐标的模 - 相机的高程

javascript 复制代码
const earthRadius = Cartesian3.magnitude(camera.positionWC) - camera.positionCartographic.height

2、在着色器中做如下转换:深度值 -> 相机坐标 -> 世界坐标,最后用片元世界坐标的模 - 相机位置对应的地球半径即可,glsl 代码如表1所示。虽然是用相机位置处的椭球半径近似替代了片元处的地球半径,但是误差很难看得出来,这种方法适用于绝大部分应用场景。

cpp 复制代码
float altitude = 0.0;
float depth = czm_unpackDepth(texture2D(depthTexture, texCoords));
if (depth == 0.0) {
	altitude = czm_infinity;
}
vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
float distance = -eyeCoordinate.z / eyeCoordinate.w;
vec4 worldCoordinate4 = czm_inverseView * eyeCoordinate;
vec3 worldCoordinate = worldCoordinate4.xyz / worldCoordinate4.w;
altitude = length(worldCoordinate.xyz) - earthRadius;

表1 glsl 中计算片元的高程

相关推荐
BillKu21 分钟前
Vue3 + TypeScript 的 Hooks 实用示例
前端·vue.js·typescript
植物系青年25 分钟前
前端玩数据库 👏 MongoDB/Mongoose 入门指南(下)
前端·mongodb·mongoose
程序饲养员28 分钟前
React从前的SPA(CSR)到现在的SSR和SSG原理解析
前端·javascript·前端框架
植物系青年29 分钟前
前端玩数据库 👏 MongoDB/Mongoose 入门指南(上)
前端·mongodb·mongoose
不懂装懂的不懂30 分钟前
【 vue + js 】引入图片、base64 编译显示图片
前端·javascript·vue.js
杨超越luckly1 小时前
HTML应用指南:利用GET请求获取全国汉堡王门店位置信息
大数据·前端·信息可视化·数据分析·html
CCChaya-软件技术教师2 小时前
24-栅格布局详解(CSS3)
前端·css·css3
BillKu2 小时前
el-input 中 select 方法使用报错:属性“select”在类型“HTMLElement”上不存在
前端·javascript·vue.js·elementui
涵信2 小时前
第一节:React 基础篇-React虚拟DOM原理及Diff算法优化策略
前端·javascript·react.js
DataFunTalk2 小时前
复旦肖仰华:大模型的数据科学!
前端·后端·算法