Ei kuvausta
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PixelPerfectCameraInternal.cs 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. using System;
  2. namespace UnityEngine.Rendering.Universal
  3. {
  4. internal interface IPixelPerfectCamera
  5. {
  6. int assetsPPU { get; set; }
  7. int refResolutionX { get; set; }
  8. int refResolutionY { get; set; }
  9. bool upscaleRT { get; set; }
  10. bool pixelSnapping { get; set; }
  11. bool cropFrameX { get; set; }
  12. bool cropFrameY { get; set; }
  13. bool stretchFill { get; set; }
  14. }
  15. [Serializable]
  16. internal class PixelPerfectCameraInternal : ISerializationCallbackReceiver
  17. {
  18. // Case 1061634:
  19. // In order for this class to survive hot reloading, we need to make the fields serializable.
  20. // Unity can't serialize an interface object, but does properly serialize UnityEngine.Object.
  21. // So we cast the reference to PixelPerfectCamera (which inherits UnityEngine.Object)
  22. // before serialization happens, and restore the interface reference after deserialization.
  23. [NonSerialized]
  24. IPixelPerfectCamera m_Component;
  25. PixelPerfectCamera m_SerializableComponent;
  26. internal float originalOrthoSize;
  27. internal bool hasPostProcessLayer;
  28. internal bool cropFrameXAndY = false;
  29. internal bool cropFrameXOrY = false;
  30. internal bool useStretchFill = false;
  31. internal int zoom = 1;
  32. internal bool useOffscreenRT = false;
  33. internal int offscreenRTWidth = 0;
  34. internal int offscreenRTHeight = 0;
  35. internal Rect pixelRect = Rect.zero;
  36. internal float orthoSize = 1.0f;
  37. internal float unitsPerPixel = 0.0f;
  38. internal int cinemachineVCamZoom = 1;
  39. internal bool requiresUpscaling = false;
  40. internal PixelPerfectCameraInternal(IPixelPerfectCamera component)
  41. {
  42. m_Component = component;
  43. }
  44. public void OnBeforeSerialize()
  45. {
  46. m_SerializableComponent = m_Component as PixelPerfectCamera;
  47. }
  48. public void OnAfterDeserialize()
  49. {
  50. if (m_SerializableComponent != null)
  51. m_Component = m_SerializableComponent;
  52. }
  53. internal void CalculateCameraProperties(int screenWidth, int screenHeight)
  54. {
  55. int assetsPPU = m_Component.assetsPPU;
  56. int refResolutionX = m_Component.refResolutionX;
  57. int refResolutionY = m_Component.refResolutionY;
  58. bool upscaleRT = m_Component.upscaleRT;
  59. bool pixelSnapping = m_Component.pixelSnapping;
  60. bool cropFrameX = m_Component.cropFrameX;
  61. bool cropFrameY = m_Component.cropFrameY;
  62. bool stretchFill = m_Component.stretchFill;
  63. cropFrameXAndY = cropFrameY && cropFrameX;
  64. cropFrameXOrY = cropFrameY || cropFrameX;
  65. useStretchFill = cropFrameXAndY && stretchFill;
  66. requiresUpscaling = useStretchFill;
  67. // zoom level (PPU scale)
  68. int verticalZoom = screenHeight / refResolutionY;
  69. int horizontalZoom = screenWidth / refResolutionX;
  70. zoom = Math.Max(1, Math.Min(verticalZoom, horizontalZoom));
  71. // off-screen RT
  72. useOffscreenRT = false;
  73. offscreenRTWidth = 0;
  74. offscreenRTHeight = 0;
  75. if (cropFrameXOrY)
  76. {
  77. useOffscreenRT = true;
  78. if (!upscaleRT)
  79. {
  80. if (cropFrameXAndY)
  81. {
  82. offscreenRTWidth = zoom * refResolutionX;
  83. offscreenRTHeight = zoom * refResolutionY;
  84. }
  85. else if (cropFrameY)
  86. {
  87. offscreenRTWidth = screenWidth;
  88. offscreenRTHeight = zoom * refResolutionY;
  89. }
  90. else // crop frame X
  91. {
  92. offscreenRTWidth = zoom * refResolutionX;
  93. offscreenRTHeight = screenHeight;
  94. }
  95. }
  96. else
  97. {
  98. if (cropFrameXAndY)
  99. {
  100. offscreenRTWidth = refResolutionX;
  101. offscreenRTHeight = refResolutionY;
  102. }
  103. else if (cropFrameY)
  104. {
  105. offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  106. offscreenRTHeight = refResolutionY;
  107. }
  108. else // crop frame X
  109. {
  110. offscreenRTWidth = refResolutionX;
  111. offscreenRTHeight = screenHeight / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  112. }
  113. }
  114. }
  115. else if (upscaleRT && zoom > 1)
  116. {
  117. useOffscreenRT = true;
  118. offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  119. offscreenRTHeight = screenHeight / zoom / 2 * 2;
  120. }
  121. // viewport
  122. if (useOffscreenRT)
  123. {
  124. // When we ask the render pipeline to create the offscreen RT for us, the size of the RT is determined by VP size.
  125. // That's why we set the VP size to be (m_OffscreenRTWidth, m_OffscreenRTHeight) here.
  126. pixelRect = new Rect(0.0f, 0.0f, offscreenRTWidth, offscreenRTHeight);
  127. }
  128. else
  129. pixelRect = Rect.zero;
  130. // orthographic size
  131. if (cropFrameY)
  132. orthoSize = (refResolutionY * 0.5f) / assetsPPU;
  133. else if (cropFrameX)
  134. {
  135. float aspect = (pixelRect == Rect.zero) ? (float)screenWidth / screenHeight : pixelRect.width / pixelRect.height;
  136. orthoSize = ((refResolutionX / aspect) * 0.5f) / assetsPPU;
  137. }
  138. else if (upscaleRT && zoom > 1)
  139. orthoSize = (offscreenRTHeight * 0.5f) / assetsPPU;
  140. else
  141. {
  142. float pixelHeight = (pixelRect == Rect.zero) ? screenHeight : pixelRect.height;
  143. orthoSize = (pixelHeight * 0.5f) / (zoom * assetsPPU);
  144. }
  145. // Camera pixel grid spacing
  146. if (upscaleRT || (!upscaleRT && pixelSnapping))
  147. unitsPerPixel = 1.0f / assetsPPU;
  148. else
  149. unitsPerPixel = 1.0f / (zoom * assetsPPU);
  150. }
  151. internal Rect CalculateFinalBlitPixelRect(int screenWidth, int screenHeight)
  152. {
  153. // This VP is used when the internal temp RT is blitted back to screen.
  154. Rect pixelRect = new Rect();
  155. if (useStretchFill)
  156. {
  157. // stretch (fit either width or height)
  158. float screenAspect = (float)screenWidth / screenHeight;
  159. float cameraAspect = (float)m_Component.refResolutionX / m_Component.refResolutionY;
  160. if (screenAspect > cameraAspect)
  161. {
  162. pixelRect.height = screenHeight;
  163. pixelRect.width = screenHeight * cameraAspect;
  164. pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
  165. pixelRect.y = 0;
  166. }
  167. else
  168. {
  169. pixelRect.width = screenWidth;
  170. pixelRect.height = screenWidth / cameraAspect;
  171. pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
  172. pixelRect.x = 0;
  173. }
  174. // Doesn't require scaling if ref resolution is a multiple of target resolution
  175. if (screenWidth % m_Component.refResolutionX == 0)
  176. {
  177. requiresUpscaling = cameraAspect < screenAspect;
  178. }
  179. else if (screenHeight % m_Component.refResolutionY == 0)
  180. {
  181. requiresUpscaling = cameraAspect > screenAspect;
  182. }
  183. }
  184. else
  185. {
  186. // center
  187. if (m_Component.upscaleRT)
  188. {
  189. pixelRect.height = zoom * offscreenRTHeight;
  190. pixelRect.width = zoom * offscreenRTWidth;
  191. }
  192. else
  193. {
  194. pixelRect.height = offscreenRTHeight;
  195. pixelRect.width = offscreenRTWidth;
  196. }
  197. pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
  198. pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
  199. }
  200. return pixelRect;
  201. }
  202. // Find a pixel-perfect orthographic size as close to targetOrthoSize as possible.
  203. internal float CorrectCinemachineOrthoSize(float targetOrthoSize)
  204. {
  205. float correctedOrthoSize;
  206. if (m_Component.upscaleRT)
  207. {
  208. cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(orthoSize / targetOrthoSize));
  209. correctedOrthoSize = orthoSize / cinemachineVCamZoom;
  210. }
  211. else
  212. {
  213. cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(zoom * orthoSize / targetOrthoSize));
  214. correctedOrthoSize = zoom * orthoSize / cinemachineVCamZoom;
  215. }
  216. // In this case the actual zoom level is cinemachineVCamZoom instead of zoom.
  217. if (!m_Component.upscaleRT && !m_Component.pixelSnapping)
  218. unitsPerPixel = 1.0f / (cinemachineVCamZoom * m_Component.assetsPPU);
  219. return correctedOrthoSize;
  220. }
  221. }
  222. }