I am trying to convert three dimensional world coordinates into coordinates on my screen. However, I do not have access to a view matrix, only to the camera's pitch and yaw angles, source coordinates (ground coordinates, not camera coordinates), target coordinates, window resolution, and field of view.
I have come up with this so far, but since I don't know how to incorporate view angles into the function, it yields incorrect results:
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;
}
The used CalcAngle
function looks like this:
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;
}
My question is: How would I create a method out of this to calculate screen coordinates using just the information I have (no view matrix, or three dimensional camera axes, I only have pitch and yaw)? If my current approach is already flawed, how would I go about creating a function that accomplishes that?
I successfully managed to fix this by subtracting the angles from CalcAngle from my view angles. Besides that, I also made sure to use the correct units for my corresponding trigonometric functions.
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;
}