主要参考:
2.Cesium DrawCommand [1] 不谈地球 画个三角形 - 岭南灯火 - 博客园 (cnblogs.com)
3.溯源:Cesium.Appearance 中的顶点着色器 - 岭南灯火 - 博客园 (cnblogs.com)
使用自定义Primitive主要是为了自定义着色器 来完成一些更加灵活自由的操作
之前使用自定义 Primitive添加三角网时 随着视角转动 三角网抖动的非常严重
查了一下才发现是向着色器传点时存在精度问题导致的
外部点的精度可能大于着色器的最大精度 所以会有抖动的现象
自定义Primitive 的代码不是重点 以后有时间了再开一个帖子讲
这个帖子主要解决精度问题导致的抖动
由于Cesium 要加载整个地球的坐标 那对于地表上的某一点可能坐标的值就非常大了 小数位数很多
这就产生了精度问题
我一开始觉得有精度问题 那直接在传点时把绝对坐标转为相对坐标 或者直接限制小数位数
这样不就可以了吗?
但是经过试验发现 这样还是存在抖动的现象 并没有解决问题
但是使用Cesium原生的api加载一些多边形时肯定是没有这个问题的
那Cesium是如何解决这个问题的呢?
就是利用了双精度+RTC
双精度是指Cesium会把本来精度较大的值拆成两个精度较小的值 这样传入着色器时就避免了因为精度不同导致的误差
代码如下
const eCartesian3 = Cesium.EncodedCartesian3.fromCartesian(cartesian);
得到的eCartesian3 中有high和low两个成员 分别记录高精度的值和低精度的值
关系为eCartesian3 .high+eCartesian3 .low=cartesian
之后便是往着色器里传值
首先定义一个attributeLocations
const attributeLocations = {
"position3DHigh": 0,
"position3DLow": 1,
}
然后生成两个VertexArray 分别对应High 和 Low
const positionBufferHigh = Cesium.Buffer.createVertexBuffer({
usage: Cesium.BufferUsage.STATIC_DRAW,
typedArray: positionsHigh,
context: frameState.context,
});
const positionBufferLow = Cesium.Buffer.createVertexBuffer({
usage: Cesium.BufferUsage.STATIC_DRAW,
typedArray: positionsLow,
context: frameState.context,
});
const vertexArray = new Cesium.VertexArray({
context: frameState.context,
attributes: [{
index: 0,
vertexBuffer: positionBufferHigh,
componentsPerAttribute: 3,
componentDatatype: Cesium.ComponentDatatype.FLOAT
},
{
index: 1,
vertexBuffer: positionBufferLow,
componentsPerAttribute: 3,
componentDatatype: Cesium.ComponentDatatype.FLOAT
}]
})
之后就是着色器的部分 只用修改顶点着色器即可
const vertexShaderText = `in vec3 position3DHigh ;
in vec3 position3DLow ;
void main() {
vec4 localpoint=czm_translateRelativeToEye(position3DHigh,position3DLow);
gl_Position = czm_modelViewProjectionRelativeToEye * localpoint;
}`
czm_translateRelativeToEye 函数是将点坐标转换到相机坐标系下(仅位移)
相机的坐标也是用双精度存储的 这就是所谓的RTC
将绝对坐标转为相对坐标 以缩小坐标的值 提高精度
效果展示:
未使用双精度时: 抖动非常严重
使用了双精度:几乎和原生的三角形api效果一致了
三角网也不再抖动