c# - 没有视图矩阵的 WorldToScreen 函数
问题描述
我正在尝试将三维世界坐标转换为屏幕上的坐标。但是,我无法访问视图矩阵,只能访问相机的俯仰角和偏航角、源坐标(地面坐标,而不是相机坐标)、目标坐标、窗口分辨率和视野。
到目前为止,我已经想出了这个,但由于我不知道如何将视角合并到函数中,它会产生不正确的结果:
public static bool WorldToScreen(Vec3 source, Vec3 target, Vec2 viewAngles, uint fov, out Vec2 screenPos)
{
screenPos = new Vec2();
Vec2 deltaAngles;
uint hWindowRes = 1920;
uint vWindowRes = 1080;
float hFov = GetFieldOfView(hWindowRes, vWindowRes, fov);
float vFov = fov;
CalcAngle(source, target, out deltaAngles);
float hOffset = (float)(Math.Tan(deltaAngles.X * Math.Cos(hFov / 2) / Math.Sin(hFov / 2) * (hWindowRes / 2)));
float hScreenPos = hWindowRes / 2 - hOffset;
float vOffset = (float)(Math.Tan(deltaAngles.Y * Math.Cos(vFov / 2) / Math.Sin(vFov / 2) * (vWindowRes / 2)));
float vScreenPos = vWindowRes / 2 - vOffset;
screenPos.X = hScreenPos;
screenPos.Y = vScreenPos;
return true;
}
使用的CalcAngle
函数如下所示:
private static bool CalcAngle(Vec3 source, Vec3 target, out Vec2 viewAngles)
{
Vec2 angles;
angles.X = (float)(((float)Math.Atan2(target.X - source.X, target.Y - source.Y)) / Math.PI * 180.0f);
angles.Y = (float)(Math.Asin((target.Z - source.Z) / Vec3.Distance(source, target)) * 180.0f / Math.PI);
viewAngles = angles;
return true;
}
我的问题是:我将如何创建一种方法来仅使用我拥有的信息(没有视图矩阵或三维相机轴,我只有俯仰和偏航)来计算屏幕坐标?如果我目前的方法已经存在缺陷,我将如何创建一个实现这一目标的函数?
解决方案
我通过从视角中减去 CalcAngle 的角度成功地解决了这个问题。除此之外,我还确保为相应的三角函数使用正确的单位。
public static bool WorldToScreen(Vec3 source, Vec3 target, Vec2 viewAngles, uint fov, out Vec2 screenPos)
{
screenPos = new Vec2();
Vec2 aimAngles;
uint hGameRes = 1920;
uint vGameRes = 1080;
float hFov = GetFieldOfView(hGameRes, vGameRes, fov);
float vFov = fov;
CalcAngle(source, target, out aimAngles);
var deltaAngles = viewAngles - aimAngles;
float hOffsetTan = (float)Math.Tan(deltaAngles.X.ToRadians());
float hOffsetCos = (float)Math.Cos((hFov / 2).ToRadians());
float hOffsetSin = (float)Math.Sin((hFov / 2).ToRadians());
float hOffset = (float)(hOffsetTan * hOffsetCos / hOffsetSin * (hGameRes / 2));
float hScreenPos = hGameRes / 2 - hOffset;
float vOffsetTan = (float)Math.Tan(deltaAngles.Y.ToRadians());
float vOffsetCos = (float)Math.Cos((vFov / 2).ToRadians());
float vOffsetSin = (float)Math.Sin((vFov / 2).ToRadians());
float vOffset = (float)(vOffsetTan * vOffsetCos / vOffsetSin * (vGameRes / 2));
float vScreenPos = vGameRes / 2 - vOffset;
screenPos.X = hScreenPos;
screenPos.Y = vScreenPos;
return true;
}
推荐阅读
- nix - Nix:将其他派生的子目录添加到 PATH
- c - 是否存在可移植的 pthread_sleep() 函数?
- r - 如何执行模拟以在 R 中找到具有给定概率的 z 分数 (x)
- angular - 如何在 Angular/RxJS 中合并两个 observable?
- c# - 如何断言 IEnumerable
- python - Selenium,pythons 网页抓取
- javascript - 使用 Javascript 提交表单后阻止导航
- php - 我怎样才能shell_exec这个powershell命令来获取进程的pid?
- reactjs - 如何在videojs中添加带有控制栏按钮列表的menuItem
- javascript - Plotly/Dash:如何使行索引独一无二?