Cesium高精度渲染解析如何使用GPU模拟64位

414 阅读2分钟

Cesium高精度渲染解析

三维场景中gpu渲染都是使用的(float 32)精度渲染,显卡只支持32位计算.

GIS场景的坐标则需要(float 64)64位来精确的表达坐标位置,我们要如何解决这个问题就必须来使用32位来模拟64位的顶点.

这里可以参考3D-Engine-Design-Virtual-Globes(Patrick Cozzi, Kevin Ring)这本书

实践

这里用到的有 position(顶点) camera(相机) mvp(透视矩阵 * 视图矩阵 * 模型变换矩阵)

我这里用glsl来解释一下如何用GPU模拟64位

第一步拆分64位顶点attribute和camera的position(高位和低位)

顶点分为两组32位浮点分别命名(position_high, position_low)

let positionBuffer = new Float64Array([658898998.54888787, 4894984878.34235345, 45645646.435353.......]); //这边随意定义一组顶点数据 
SplitDouble(value: number): number[] { //拆分函数 
let hi = Float32Array.from([value])[0]; 
let low = value - hi; 
return [hi, low]; 
} 
let positionHighBuffer = new Float32Array(positionBuffer.length); 
let positionLowBuffer = new Float32Array(positionBuffer.length); 
// ----- 拆分 ------- 
for (let index = 0; index < positionBuffer.length; index++) { 
const position = positionBuffer[index]; 
let hi_low = SplitDouble(position); 
positionHighBuffer[index] = hi_low[0]; 
positionLowBuffer[index] = hi_low[1]; 
} // ----- 拆分 ------- 
// 分别把positionHighBuffer(position_high), positionLowBuffer(position_low) 作为attribute 传入到顶点着色器

我们来拆分相机坐标(camera_pos_high,camera_pos_low),在对 mv(viewMatrix) 做一下处理命名为(MVP_RTE)

// 还是上面那种方法 
let cameraPos = { x:54498832.4898989, y:48978988.46889999, z:448484789.415747488 }; 
let cameraPos_xHL = SplitDouble(cameraPos.x); 
let cameraPos_yHL = SplitDouble(cameraPos.y); 
let cameraPos_zHL = SplitDouble(cameraPos.z); 
let camera_pos_high = { x: cameraPos_xHL[0], y: cameraPos_yHL[0], z: cameraPos_zHL[0], } 
let camera_pos_low = { x: cameraPos_xHL[1], y: cameraPos_yHL[1], z: cameraPos_zHL[1], } 
let viewMatrix = camera.viewMatrix let projectionMatrix = camera.projectionMatrix viewMatrix[12] = 0; 
viewMatrix[13] = 0; 
viewMatrix[14] = 0; 
let MVP_RTE = camera.viewMatrix.multiply(projectionMatrix) 
// 分别传入顶点着色器 camera_pos_high camera_pos_low MVP_RTE

来编写顶点着色器shader

let vs = `
          attribute vec3 position_high; 
          attribute vec3 position_low;
          uniform vec3 camera_pos_high; 
          uniform vec3 camera_pos_low; 
          uniform mat4 MVP_RTE; 
          void main() { 
          vec3 high_delta = position_high - camera_pos_high; 
          vec3 low_delta = position_low - camera_pos_low; 
          gl_Position = MVP_RTE * vec4(high_delta + low_delta, 1.0); 
          }
          `

到这里所有的工作就做完了

前后对比

未做处理 image.png 做了处理 image.png