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);
}
`
到这里所有的工作就做完了
前后对比
未做处理
做了处理
