Advertisement
PirateHearts

Screenspace position from worldspace position

Apr 25th, 2018
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.42 KB | None | 0 0
  1. #include "NScreenSpace.h"
  2. #include "NUtilDefs.h"
  3. #include "NGeometry.h"
  4.  
  5. #include "NBaseGame.h"
  6. #include "NFont.h"
  7.  
  8. NScreenSpaceOutput NScreenSpace::GetScreenSpacePosition(const NVec3& Position, NCamera* pCamera, const NScreenSpaceParams& Params)
  9. {
  10. opt_assert(pCamera);
  11.  
  12. // Solving the edge-of-screen HUD indicator problem (maybe reusable in Banon!):
  13.  
  14. // 0. We may wish to define a subsection of the screen for title safety within which indicators are clamped.
  15. // This could be implemented as a scalar on the tangent of the camera's FOV for considering elements to be "off-screen."
  16.  
  17. // 1. If an element is "off-screen" (whether for real or as determined by a title safety region, etc.),
  18. // it should be denoted by an angle, not a position in screen space. This is to prevent bugs when, e.g.,
  19. // lerping between positions on the opposite sides of the screen.
  20.  
  21. // 2. Elements in front of the camera are projected into screen space and clamped. An angle can then be found with an atan2().
  22.  
  23. // 3. Elements behind the camera are probably calculated as an angle relative to...the facing angle?
  24. // The "FPS forward" vector? Looking up/down is where this gets doubly complicated.
  25.  
  26. // 4. Once I have an angle, I project its normalized vector onto the edge of the region. Is this elliptical or circular?
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34. NVec3 FlatForward = pCamera->getFwdFPS();
  35. NVec3 FlatUp = pCamera->getUpFPS();
  36. NVec3 FlatLeft = pCamera->getLeftFPS();
  37.  
  38. NVec3 PositionProjectedOntoFlatForwardLeftPlane = Position - Projection(Position - pCamera->getPos(), FlatUp);
  39. PositionProjectedOntoFlatForwardLeftPlane;
  40.  
  41. NPlane FlatForwardPlane(FlatForward, pCamera->getPos());
  42. NPlane FlatUpPlane(FlatUp, pCamera->getPos());
  43. float FlatForwardDot = Dot(FlatForward, Normalize(PositionProjectedOntoFlatForwardLeftPlane - pCamera->getPos()));
  44. float FlatLeftDot = Dot(FlatLeft, Normalize(PositionProjectedOntoFlatForwardLeftPlane - pCamera->getPos()));
  45.  
  46. float FlatForwardAngle = acos(Saturate(FlatForwardDot));
  47.  
  48. float ToLeft = 0.0f;
  49. float ToRight = 0.0f;
  50.  
  51. if (FlatLeftDot >= 0.0f)
  52. {
  53. // It's on our left side, so FlatForwardAngle is the angle it is to our left.
  54. ToLeft = (HALF_PI - FlatForwardAngle);
  55. ToRight = (HALF_PI + FlatForwardAngle);
  56. }
  57. else
  58. {
  59. // It's on our right side, so FlatForwardAngle is the angle it is to our right.
  60. ToLeft = (HALF_PI + FlatForwardAngle);
  61. ToRight = (HALF_PI - FlatForwardAngle);
  62. }
  63.  
  64. NMat4 ViewMat1 = CreateViewMatrix(pCamera->getPos(), FlatForward, FlatLeft, FlatUp);
  65. NMat4 ViewMat2 = pCamera->getViewMatrix();
  66.  
  67. ViewMat1, ViewMat2;
  68.  
  69. NMat4 RotLeftMat = CreateRotationMatrix(FlatUp, ToLeft);
  70. NMat4 RotRightMat = CreateRotationMatrix(FlatUp, -ToRight);
  71.  
  72. NVec3 LeftPos = (RotLeftMat * (Position - pCamera->getPos()));// + pCamera->getPos();
  73. NVec3 RightPos = (RotRightMat * (Position - pCamera->getPos()));// + pCamera->getPos();
  74.  
  75. NVec3 ProjLeftPos = LeftPos - Projection(LeftPos, FlatForward);
  76. NVec3 ProjRightPos = RightPos - Projection(RightPos, FlatForward);
  77.  
  78. ProjLeftPos, ProjRightPos;
  79.  
  80. // Okay, these are wrong. I DON'T actually want these to be the point projected onto the camera plane;
  81. // I want them to be the point projected right at the edge of the title safety region.
  82. // Then I also don't need the lerp between the edge of that region and the camera plane;
  83. // as soon as it's outside that region, I lerp around the bottom of the screen.
  84. // Actually, no, that would break for things just ABOVE the title safety region. That's bad.
  85. // Hrm. Maybe this is okay for now?
  86. // Or maybe I just need to care about left/right edges of the region.
  87. // There's also an issue when looking some distance up or down and then MOVING past a point of interest until it is behind the plane rather than TURNING past.
  88. ProjLeftPos = (/*CreateTranslationMatrix(-pCamera->getPos()) **/ CreateRotationMatrix(FlatForward, FlatLeft, FlatUp)) * ProjLeftPos;
  89. ProjRightPos = (/*CreateTranslationMatrix(-pCamera->getPos()) **/ CreateRotationMatrix(FlatForward, FlatLeft, FlatUp)) * ProjRightPos;
  90.  
  91. float LeftAngle = atan2(ProjLeftPos.y, ProjLeftPos.z);
  92. float RightAngle = atan2(ProjRightPos.y, ProjRightPos.z);
  93.  
  94. opt_assert(LeftAngle >= 0.0f && LeftAngle <= PI);
  95. opt_assert(RightAngle <= 0.0f && RightAngle >= -PI);
  96.  
  97. LeftAngle, RightAngle;
  98.  
  99.  
  100.  
  101.  
  102. // These are in degrees.
  103. float VFOV = pCamera->getFOV();
  104. float HFOV = HorizontalFOV(VFOV, pCamera->getAspectRatio());
  105. // Let's take the diagonal FOV and use that as the starting point for where we lerp to the camera plane angles.
  106. float HFOVRad = HFOV * DEG2RAD;
  107. float VFOVRad = VFOV * DEG2RAD;
  108. float TanHalfHFOV = tan(HFOVRad * 0.5f);
  109. float TanHalfVFOV = tan(VFOVRad * 0.5f);
  110. TanHalfHFOV *= Params.TitleSafetyWidth;
  111. TanHalfVFOV *= Params.TitleSafetyHeight;
  112. float TanHalfDFOV = sqrt(((TanHalfHFOV)*(TanHalfHFOV))+((TanHalfVFOV)*(TanHalfVFOV)));
  113. float HalfDFOVRad = atan(TanHalfDFOV);// * 2.0f;
  114. float HalfDFOV = HalfDFOVRad * RAD2DEG;
  115. HalfDFOV;
  116.  
  117. float LerpStartCos = cos(HalfDFOVRad);
  118. float LerpEndCos = 0.0f;
  119.  
  120. float Interpolant = Dot(pCamera->getForward(), Normalize(Position - pCamera->getPos()));
  121.  
  122. Interpolant = Saturate(Normalize(Interpolant, LerpStartCos, LerpEndCos));
  123.  
  124. // Now we use this Interpolant to lerp between the angle calculated from the camera-projected position and the angle on the left or right side as appropriate.
  125. Interpolant;
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134. NScreenSpaceOutput RetVal;
  135.  
  136. float DotProduct = Dot(Position - pCamera->getPos(), pCamera->getForward());
  137. if (DotProduct > 0.0f)
  138. {
  139. // It's in front of the camera. We should be able to use its screen-space-projected position directly.
  140. NVec3 Projected = pCamera->project(Position);
  141. Projected;
  142.  
  143. ANCHOR;
  144.  
  145. if (Abs(Projected.x) < Params.TitleSafetyWidth &&
  146. Abs(Projected.y) < Params.TitleSafetyHeight)
  147. {
  148. // It's within the title safety region.
  149. // We can show an icon directly over the point of interest.
  150. ANCHOR;
  151.  
  152. RetVal.PositionClassification = ESSP_WithinTitleSafetyRegion;
  153.  
  154. RetVal.Position = Projected;
  155. RetVal.AngleToPosition = 0.0f;
  156. }
  157. else
  158. {
  159. // It's not. We should treat it as "off-screen" regardless of position,
  160. // and we need to be sure this aligns with any behind-the-plane behavior.
  161. ANCHOR;
  162.  
  163. RetVal.PositionClassification = ESSP_BetweenTitleSafetyRegionAndCameraPlane;
  164.  
  165. // Here is where we use Interpolant.
  166. // But first we need to calculate the angle of the projected point.
  167. float ProjAngle = atan2(-Projected.x, Projected.y);
  168.  
  169. // TODO: Make sure we take the nearest direction here.
  170. // We should just need to know left/right side.
  171.  
  172. opt_assert(ProjAngle >= -PI && ProjAngle <= +PI);
  173. float LerpedAngle = 0.0f;
  174. if (ProjAngle >= 0.0f)
  175. {
  176. LerpedAngle = Lerp(ProjAngle, LeftAngle, Interpolant);
  177. }
  178. else
  179. {
  180. LerpedAngle = Lerp(ProjAngle, RightAngle, Interpolant);
  181. }
  182.  
  183. RetVal.Position = NVec2(-sin(LerpedAngle), cos(LerpedAngle));
  184. RetVal.Position = RetVal.Position / Max(Abs(RetVal.Position.x) / Params.TitleSafetyWidth, Abs(RetVal.Position.y) / Params.TitleSafetyHeight);
  185.  
  186. RetVal.AngleToPosition = LerpedAngle;
  187. }
  188. }
  189. else
  190. {
  191. // It's behind the camera. Do something else.
  192. ANCHOR;
  193.  
  194. RetVal.PositionClassification = ESSP_BehindCameraPlane;
  195.  
  196. // Lerp from LeftAngle to RightAngle based on FPS facing.
  197. float LeftDot = Dot(FlatLeft, Normalize(Position - pCamera->getPos()));
  198. while (RightAngle < LeftAngle)
  199. {
  200. RightAngle += TAU;
  201. }
  202. float LerpedAngle = Lerp(LeftAngle, RightAngle, Saturate(Normalize(LeftDot, +1.0f, -1.0f)));
  203. RetVal.Position = NVec2(-sin(LerpedAngle), cos(LerpedAngle));
  204. RetVal.Position = RetVal.Position / Max(Abs(RetVal.Position.x) / Params.TitleSafetyWidth, Abs(RetVal.Position.y) / Params.TitleSafetyHeight);
  205.  
  206. while (LerpedAngle < -PI) {LerpedAngle += TAU;}
  207. while (LerpedAngle > +PI) {LerpedAngle -= TAU;}
  208.  
  209. RetVal.AngleToPosition = LerpedAngle;
  210. }
  211.  
  212. //ANCHOR;
  213. //NFont* TheFont = NBaseGame::GetInstance()->GetDefaultInGameFont();
  214. //float dx = 0.0f;
  215. //float dy = 0.0f;
  216. //TheFont->MeasureText_Legacy("X",1,dx,dy);
  217. //TheFont->DrawText_Legacy("X",1,
  218. // Lerp(0.0f, NBaseGame::GetInstance()->SCREEN_WIDTH / ((float)NBaseGame::GetInstance()->SCREEN_HEIGHT / 1080.0f)/*(float)NBaseGame::GetInstance()->SCREEN_WIDTH*/, Normalize(RetVal.Position.x, -1.0f, +1.0f)) - (dx*0.5f),
  219. // Lerp(0.0f, 1080.0f/*(float)NBaseGame::GetInstance()->SCREEN_HEIGHT*/, Normalize(RetVal.Position.y, +1.0f, -1.0f)) - (dy*0.5f));
  220.  
  221. return RetVal;
  222. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement