PixelPerfectCameraInternal.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. using System;
  2. namespace UnityEngine.Experimental.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 PixelPerfectCameraInternal(IPixelPerfectCamera component)
  40. {
  41. m_Component = component;
  42. }
  43. public void OnBeforeSerialize()
  44. {
  45. m_SerializableComponent = m_Component as PixelPerfectCamera;
  46. }
  47. public void OnAfterDeserialize()
  48. {
  49. if (m_SerializableComponent != null)
  50. m_Component = m_SerializableComponent;
  51. }
  52. internal void CalculateCameraProperties(int screenWidth, int screenHeight)
  53. {
  54. int assetsPPU = m_Component.assetsPPU;
  55. int refResolutionX = m_Component.refResolutionX;
  56. int refResolutionY = m_Component.refResolutionY;
  57. bool upscaleRT = m_Component.upscaleRT;
  58. bool pixelSnapping = m_Component.pixelSnapping;
  59. bool cropFrameX = m_Component.cropFrameX;
  60. bool cropFrameY = m_Component.cropFrameY;
  61. bool stretchFill = m_Component.stretchFill;
  62. cropFrameXAndY = cropFrameY && cropFrameX;
  63. cropFrameXOrY = cropFrameY || cropFrameX;
  64. useStretchFill = cropFrameXAndY && stretchFill;
  65. // zoom level (PPU scale)
  66. int verticalZoom = screenHeight / refResolutionY;
  67. int horizontalZoom = screenWidth / refResolutionX;
  68. zoom = Math.Max(1, Math.Min(verticalZoom, horizontalZoom));
  69. // off-screen RT
  70. useOffscreenRT = false;
  71. offscreenRTWidth = 0;
  72. offscreenRTHeight = 0;
  73. if (cropFrameXOrY)
  74. {
  75. useOffscreenRT = true;
  76. if (!upscaleRT)
  77. {
  78. if (cropFrameXAndY)
  79. {
  80. offscreenRTWidth = zoom * refResolutionX;
  81. offscreenRTHeight = zoom * refResolutionY;
  82. }
  83. else if (cropFrameY)
  84. {
  85. offscreenRTWidth = screenWidth;
  86. offscreenRTHeight = zoom * refResolutionY;
  87. }
  88. else // crop frame X
  89. {
  90. offscreenRTWidth = zoom * refResolutionX;
  91. offscreenRTHeight = screenHeight;
  92. }
  93. }
  94. else
  95. {
  96. if (cropFrameXAndY)
  97. {
  98. offscreenRTWidth = refResolutionX;
  99. offscreenRTHeight = refResolutionY;
  100. }
  101. else if (cropFrameY)
  102. {
  103. offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  104. offscreenRTHeight = refResolutionY;
  105. }
  106. else // crop frame X
  107. {
  108. offscreenRTWidth = refResolutionX;
  109. offscreenRTHeight = screenHeight / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  110. }
  111. }
  112. }
  113. else if (upscaleRT && zoom > 1)
  114. {
  115. useOffscreenRT = true;
  116. offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  117. offscreenRTHeight = screenHeight / zoom / 2 * 2;
  118. }
  119. // viewport
  120. if (useOffscreenRT)
  121. {
  122. // When we ask the render pipeline to create the offscreen RT for us, the size of the RT is determined by VP size.
  123. // That's why we set the VP size to be (m_OffscreenRTWidth, m_OffscreenRTHeight) here.
  124. pixelRect = new Rect(0.0f, 0.0f, offscreenRTWidth, offscreenRTHeight);
  125. }
  126. else
  127. pixelRect = Rect.zero;
  128. // orthographic size
  129. if (cropFrameY)
  130. orthoSize = (refResolutionY * 0.5f) / assetsPPU;
  131. else if (cropFrameX)
  132. {
  133. float aspect = (pixelRect == Rect.zero) ? (float)screenWidth / screenHeight : pixelRect.width / pixelRect.height;
  134. orthoSize = ((refResolutionX / aspect) * 0.5f) / assetsPPU;
  135. }
  136. else if (upscaleRT && zoom > 1)
  137. orthoSize = (offscreenRTHeight * 0.5f) / assetsPPU;
  138. else
  139. {
  140. float pixelHeight = (pixelRect == Rect.zero) ? screenHeight : pixelRect.height;
  141. orthoSize = (pixelHeight * 0.5f) / (zoom * assetsPPU);
  142. }
  143. // Camera pixel grid spacing
  144. if (upscaleRT || (!upscaleRT && pixelSnapping))
  145. unitsPerPixel = 1.0f / assetsPPU;
  146. else
  147. unitsPerPixel = 1.0f / (zoom * assetsPPU);
  148. }
  149. internal Rect CalculateFinalBlitPixelRect(int screenWidth, int screenHeight)
  150. {
  151. // This VP is used when the internal temp RT is blitted back to screen.
  152. Rect pixelRect = new Rect();
  153. if (useStretchFill)
  154. {
  155. // stretch (fit either width or height)
  156. float screenAspect = (float)screenWidth / screenHeight;
  157. float cameraAspect = (float)m_Component.refResolutionX / m_Component.refResolutionY;
  158. if (screenAspect > cameraAspect)
  159. {
  160. pixelRect.height = screenHeight;
  161. pixelRect.width = screenHeight * cameraAspect;
  162. pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
  163. pixelRect.y = 0;
  164. }
  165. else
  166. {
  167. pixelRect.width = screenWidth;
  168. pixelRect.height = screenWidth / cameraAspect;
  169. pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
  170. pixelRect.x = 0;
  171. }
  172. }
  173. else
  174. {
  175. // center
  176. if (m_Component.upscaleRT)
  177. {
  178. pixelRect.height = zoom * offscreenRTHeight;
  179. pixelRect.width = zoom * offscreenRTWidth;
  180. }
  181. else
  182. {
  183. pixelRect.height = offscreenRTHeight;
  184. pixelRect.width = offscreenRTWidth;
  185. }
  186. pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
  187. pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
  188. }
  189. return pixelRect;
  190. }
  191. // Find a pixel-perfect orthographic size as close to targetOrthoSize as possible.
  192. internal float CorrectCinemachineOrthoSize(float targetOrthoSize)
  193. {
  194. float correctedOrthoSize;
  195. if (m_Component.upscaleRT)
  196. {
  197. cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(orthoSize / targetOrthoSize));
  198. correctedOrthoSize = orthoSize / cinemachineVCamZoom;
  199. }
  200. else
  201. {
  202. cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(zoom * orthoSize / targetOrthoSize));
  203. correctedOrthoSize = zoom * orthoSize / cinemachineVCamZoom;
  204. }
  205. // In this case the actual zoom level is cinemachineVCamZoom instead of zoom.
  206. if (!m_Component.upscaleRT && !m_Component.pixelSnapping)
  207. unitsPerPixel = 1.0f / (cinemachineVCamZoom * m_Component.assetsPPU);
  208. return correctedOrthoSize;
  209. }
  210. }
  211. }