一、说明
之前接触过3DTile 的格式说明,一直对geometricError(单位是米)没有透彻了解,从表面意思“几何误差”简直是让人一头雾水,今天就透过代码看本质,geometricError 表达到底是什么意思。
二、 核心代码算法
在 Cesium3DTile中的getScreenSpaceError 的方法,下面列出了核心代码。
var camera = frameState.camera;
var frustum = camera.frustum;
var context = frameState.context;
var width = context.drawingBufferWidth;
var height = context.drawingBufferHeight;
var error;
// Avoid divide by zero when viewer is inside the tile
var distance = Math.max(this._distanceToCamera, CesiumMath.EPSILON7);
var sseDenominator = camera.frustum.sseDenominator;
error = (geometricError * height) / (distance * sseDenominator);
error = (geometricError *屏幕高度)/(到相机距离 * 比例分母)
啊! 比例分母是什么的东东,看下面代码。
frustum._sseDenominator = 2.0 * Math.tan(0.5 * frustum._fovy);
在这里先说一个结论:geometricError 就是一个对象外包球的直径,会根据相机位置计算投影屏幕所站的像素大小。下面就分析这个算法过程。
三、 算法分析
先看下面这个图:
首先要指定fov角的一半对应也是屏幕高的一半
tan(a)的值约等于,当距离比geometricError大很多倍的时候。
t
a
n
(
α
)
≈
g
e
o
m
e
t
r
i
c
E
r
r
o
r
(
2
∗
d
i
s
t
a
n
c
e
)
tan(\alpha) \approx \frac {geometricError} {(2*distance)}
tan(α)≈(2∗distance)geometricError
求PixeSize 就是geometricError 投影在屏幕上的一半
t
a
n
(
α
)
t
a
n
(
0.5
∗
f
o
v
)
=
P
i
x
e
S
i
z
e
h
e
i
g
h
t
2
\frac {tan(\alpha)} {tan(0.5*fov)}= \frac {PixeSize} {\frac {height} {2}}
tan(0.5∗fov)tan(α)=2heightPixeSize
P
i
x
e
S
i
z
e
=
t
a
n
(
α
)
t
a
n
(
0.5
∗
f
o
v
)
∗
h
e
i
g
h
t
2
PixeSize=\frac {tan(\alpha)} {tan(0.5*fov)}*{\frac {height} {2}}
PixeSize=tan(0.5∗fov)tan(α)∗2height
把tan(a)带入,同时PixeSize*2
2
∗
P
i
x
e
S
i
z
e
=
2
∗
t
a
n
(
α
)
t
a
n
(
0.5
∗
f
o
v
)
∗
h
e
i
g
h
t
2
2*PixeSize=2* \frac {tan(\alpha)} {tan(0.5*fov)}*{\frac {height} {2}}
2∗PixeSize=2∗tan(0.5∗fov)tan(α)∗2height
2
∗
P
i
x
e
S
i
z
e
=
2
∗
g
e
o
m
e
t
r
i
c
E
r
r
o
r
(
2
∗
d
i
s
t
a
n
c
e
)
∗
1
t
a
n
(
0.5
∗
f
o
v
)
∗
h
e
i
g
h
t
2
2*PixeSize=2* \frac {geometricError} {(2*distance)}* \frac {1} {tan(0.5*fov)}*{\frac {height} {2}}
2∗PixeSize=2∗(2∗distance)geometricError∗tan(0.5∗fov)1∗2height
e
r
r
o
=
2
∗
P
i
x
e
S
i
z
e
=
g
e
o
m
e
t
r
i
c
E
r
r
o
r
∗
h
e
i
g
h
t
d
i
s
t
a
n
c
e
∗
2
∗
t
a
n
(
0.5
∗
f
o
v
)
erro=2*PixeSize= \frac {geometricError * height} {distance*2*tan(0.5*fov)}
erro=2∗PixeSize=distance∗2∗tan(0.5∗fov)geometricError∗height
可以看出最终和Cesium 中的公式一样了,可能有同学疑问了tan函数是个曲线,不能这么等比划分。
我把角度1-30做了一个tan值的曲线,表现就类似一个直线嘛。
四、总结
- 从代码算法中可以看出geometricError就是一个对象外包球的直径,会根据相机位置计算投影屏幕所站的像素大小。
- 个人很不喜欢3Dtile 文档中给出解释,简直让人难以理解啊
- 这个算法核心原理是根据角度值比算投影像素值,当然计算一个大约值的投影到屏幕像素。
- 文中若有不正之处,欢迎指出,写这篇文章也只是想让大家更简单了解3dTile 中的geometricError含义