如何计算 3D 对象的视角
How to calculate the viewing angle of an object in 3D
如下所示,假设有一个虚拟相机指向一个物体,并且两者都由相对于全局坐标系的方向和位置定义。图中黑色为GCS,蓝色为LCS。
某些物体(例如本例中的屏幕或 LED)具有视角。它们只能被看到,例如,如果与观察者的角度在±70°以内
为了解决这个问题,到目前为止我已经采取了以下伪代码演示的步骤。在适用的情况下,我们在右手坐标系中工作,使用按 ZYX 顺序应用的外部旋转。
LEDToWorldTransform = LED.Transform;
CameraToWorldTransform = Camera.Transform;
WorldToCameraTransform = CameraToWorldTransform.Inverse;
CameraToLEDTransform = WorldToCameraTransform * LEDToWorldTransform;
据我了解,CameraToLEDTransform 现在应该包含 LED 相对于相机坐标系的平移和旋转。出于可视化目的:
现在这就是我卡住的地方,查看 CameraToLEDTransform
的欧拉分量我想我们可以得出结论,相对于相机坐标系的旋转的 Z 分量不会影响视图引领。我尝试了以下我不确定是否正确的方法。请注意,在第三步中,我试图翻转其中一个 Z 轴的方向,使它们指向相同的方向
R_Z, R_Y, R_X = CameraToLEDTransform.Rotation.Eulers
CameraToLEDTransform.Rotation.Eulers = 0, R_Y, R_X
CameraToLEDTransform.Rotation *= Rotation.AngleAxis[180deg,X]
Angle, Axis = CameraToLEDTransform.Rotation.AngleAxis
这给出了一个看起来正确的答案,但是我怀疑按照我的逻辑可能有问题我也应该能够用以下内容替换第三步:
CameraToLEDTransform.Rotation *= Rotation.AngleAxis[180deg,Y]
然而,事实并非如此,我得到了不同的(当然是错误的)答案。这种方法可能是完全错误的,我当然不明白为什么在这种情况下绕 X 旋转 180 度与绕 Y 旋转 180 度不同。也许另一种方法是使用点积来计算角度,但我认为这只适用于两个向量而不是两个旋转。似乎基于两个对象的方向投影两个新向量将是一个非常绕的方法...
使用点积不是迂回的方法,它是正确的方法。您必须使用相机的视图方向矢量与法线(即从观察者到相关 LED/object 的矢量)之间的点积来获得所需角度的余弦值。如果对象是 表面,如屏幕,您可能需要使用表面的法线。
// normalized returns a unit vector
Vector3 normal = (led.position - observer.position).Normalized();
Vector3 lookDirection = observer.lookDirection; // Should be a unit vector
float cosAngle = Vector3.Dot(normal, lookDirection);
在检查角度是否在要求的范围内时,我们可以使用 cos
函数的以下 属性 来避免 acos
调用:
If -angle <= theta <= angle
, cos(theta) >= cos(angle)
. (Try it out!)
您的支票如下:
// You can constantize or precompute this
float cosViewingAngle = cos(deg2rad(70));
bool inViewingAngle = cosAngle >= cosViewingAngle;
如下所示,假设有一个虚拟相机指向一个物体,并且两者都由相对于全局坐标系的方向和位置定义。图中黑色为GCS,蓝色为LCS。
某些物体(例如本例中的屏幕或 LED)具有视角。它们只能被看到,例如,如果与观察者的角度在±70°以内
为了解决这个问题,到目前为止我已经采取了以下伪代码演示的步骤。在适用的情况下,我们在右手坐标系中工作,使用按 ZYX 顺序应用的外部旋转。
LEDToWorldTransform = LED.Transform;
CameraToWorldTransform = Camera.Transform;
WorldToCameraTransform = CameraToWorldTransform.Inverse;
CameraToLEDTransform = WorldToCameraTransform * LEDToWorldTransform;
据我了解,CameraToLEDTransform 现在应该包含 LED 相对于相机坐标系的平移和旋转。出于可视化目的:
现在这就是我卡住的地方,查看 CameraToLEDTransform
的欧拉分量我想我们可以得出结论,相对于相机坐标系的旋转的 Z 分量不会影响视图引领。我尝试了以下我不确定是否正确的方法。请注意,在第三步中,我试图翻转其中一个 Z 轴的方向,使它们指向相同的方向
R_Z, R_Y, R_X = CameraToLEDTransform.Rotation.Eulers
CameraToLEDTransform.Rotation.Eulers = 0, R_Y, R_X
CameraToLEDTransform.Rotation *= Rotation.AngleAxis[180deg,X]
Angle, Axis = CameraToLEDTransform.Rotation.AngleAxis
这给出了一个看起来正确的答案,但是我怀疑按照我的逻辑可能有问题我也应该能够用以下内容替换第三步:
CameraToLEDTransform.Rotation *= Rotation.AngleAxis[180deg,Y]
然而,事实并非如此,我得到了不同的(当然是错误的)答案。这种方法可能是完全错误的,我当然不明白为什么在这种情况下绕 X 旋转 180 度与绕 Y 旋转 180 度不同。也许另一种方法是使用点积来计算角度,但我认为这只适用于两个向量而不是两个旋转。似乎基于两个对象的方向投影两个新向量将是一个非常绕的方法...
使用点积不是迂回的方法,它是正确的方法。您必须使用相机的视图方向矢量与法线(即从观察者到相关 LED/object 的矢量)之间的点积来获得所需角度的余弦值。如果对象是 表面,如屏幕,您可能需要使用表面的法线。
// normalized returns a unit vector
Vector3 normal = (led.position - observer.position).Normalized();
Vector3 lookDirection = observer.lookDirection; // Should be a unit vector
float cosAngle = Vector3.Dot(normal, lookDirection);
在检查角度是否在要求的范围内时,我们可以使用 cos
函数的以下 属性 来避免 acos
调用:
If
-angle <= theta <= angle
,cos(theta) >= cos(angle)
. (Try it out!)
您的支票如下:
// You can constantize or precompute this
float cosViewingAngle = cos(deg2rad(70));
bool inViewingAngle = cosAngle >= cosViewingAngle;