原理
对于地球来讲,除了进行视锥体剔除之外,还要进行遮挡体剔除,地球就是一个巨大的遮挡体,地球背面的物体应该被剔除,即图中灰色阴影部分不该显示。

如图所示C为视点,T为要剔除的点(假设我们已经选到了一个合适的点,该点不显示则整个物体必然不会显示),H为视点与地球的切点,C为球心
要实现地平线剔除,需要T在灰色阴影体中,需要满足两个条件
- ∣VQ∣>∣VP∣
- ∠α>∠β
实现
1.∣VQ∣>∣VP∣的推导
首先明确已知点为 V,T,C
∣VQ∣=∣VT∣∗cos(β)=∣VT∣∗VT^⋅VC^=VT⋅VC^
又因为:
sinα=∣VC∣∣HC∣=∣HC∣∣PC∣
则为单位球时:
∣PC∣=∣VC∣∣HC∣2=∣VC∣1而∣VP∣=∣VC∣−∣PC∣=∣VC∣−∣VC∣1VT⋅VC^>∣VC∣−∣VC∣1VT⋅VC>∣VC∣2−1
2.∠α>∠β的推导
cosα=∣VC∣∣VH∣cosβ=∣VT∣∗∣VC∣VT⋅VC
若要使得
∠α>∠β,则
cosα<cosβ∣VC∣∣VH∣<∣VT∣∗∣VC∣VT⋅VC∣VH∣<∣VT∣VT⋅VC
又由于VT与VC的夹角小于90度,则VT⋅VC>0,两边同时平方,符号不变,则为:
∣VH∣2<∣VT∣2(VT⋅VC)2
而当为单位球时,∣VH∣2=∣VC∣2−1
∣VC∣2−1<∣VT∣2(VT⋅VC)2
代码
在cesium中实现的关键代码如下:
var rX = 6378137.0;
var rY = 6378137.0;
var rZ = 6356752.3142451793;
var cvX = cameraPosition.x / rX;
var cvY = cameraPosition.y / rY;
var cvZ = cameraPosition.z / rZ;
var vhMagnitudeSquared = cvX * cvX + cvY * cvY + cvZ * cvZ - 1.0;
var tX = position.x / rX;
var tY = position.y / rY;
var tZ = position.z / rZ;
var vtX = tX - cvX;
var vtY = tY - cvY;
var vtZ = tZ - cvZ;
var vtMagnitudeSquared = vtX * vtX + vtY * vtY + vtZ * vtZ;
var vtDotVc = -(vtX * cvX + vtY * cvY + vtZ * cvZ);
var isOccluded = vtDotVc > vhMagnitudeSquared &&
vtDotVc * vtDotVc / vtMagnitudeSquared > vhMagnitudeSquared;