Brak opisu
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.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using System;
  2. namespace UnityEngine.U2D
  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. if (!upscaleRT)
  76. {
  77. if (useStretchFill)
  78. {
  79. useOffscreenRT = true;
  80. offscreenRTWidth = zoom * refResolutionX;
  81. offscreenRTHeight = zoom * refResolutionY;
  82. }
  83. }
  84. else
  85. {
  86. useOffscreenRT = true;
  87. if (cropFrameXAndY)
  88. {
  89. offscreenRTWidth = refResolutionX;
  90. offscreenRTHeight = refResolutionY;
  91. }
  92. else if (cropFrameY)
  93. {
  94. offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  95. offscreenRTHeight = refResolutionY;
  96. }
  97. else // crop frame X
  98. {
  99. offscreenRTWidth = refResolutionX;
  100. offscreenRTHeight = screenHeight / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  101. }
  102. }
  103. }
  104. else if (upscaleRT && zoom > 1)
  105. {
  106. useOffscreenRT = true;
  107. offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
  108. offscreenRTHeight = screenHeight / zoom / 2 * 2;
  109. }
  110. // viewport
  111. pixelRect = Rect.zero;
  112. if (cropFrameXOrY && !upscaleRT && !useStretchFill)
  113. {
  114. if (cropFrameXAndY)
  115. {
  116. pixelRect.width = zoom * refResolutionX;
  117. pixelRect.height = zoom * refResolutionY;
  118. }
  119. else if (cropFrameY)
  120. {
  121. pixelRect.width = screenWidth;
  122. pixelRect.height = zoom * refResolutionY;
  123. }
  124. else // crop frame X
  125. {
  126. pixelRect.width = zoom * refResolutionX;
  127. pixelRect.height = screenHeight;
  128. }
  129. pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
  130. pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
  131. }
  132. else if (useOffscreenRT)
  133. {
  134. // When Camera.forceIntoRenderTexture is true, the size of the internal RT is determined by VP size.
  135. // That's why we set the VP size to be (m_OffscreenRTWidth, m_OffscreenRTHeight) here.
  136. pixelRect = new Rect(0.0f, 0.0f, offscreenRTWidth, offscreenRTHeight);
  137. }
  138. // orthographic size
  139. if (cropFrameY)
  140. orthoSize = (refResolutionY * 0.5f) / assetsPPU;
  141. else if (cropFrameX)
  142. {
  143. float aspect = (pixelRect == Rect.zero) ? (float)screenWidth / screenHeight : pixelRect.width / pixelRect.height;
  144. orthoSize = ((refResolutionX / aspect) * 0.5f) / assetsPPU;
  145. }
  146. else if (upscaleRT && zoom > 1)
  147. orthoSize = (offscreenRTHeight * 0.5f) / assetsPPU;
  148. else
  149. {
  150. float pixelHeight = (pixelRect == Rect.zero) ? screenHeight : pixelRect.height;
  151. orthoSize = (pixelHeight * 0.5f) / (zoom * assetsPPU);
  152. }
  153. // Camera pixel grid spacing
  154. if (upscaleRT || (!upscaleRT && pixelSnapping))
  155. unitsPerPixel = 1.0f / assetsPPU;
  156. else
  157. unitsPerPixel = 1.0f / (zoom * assetsPPU);
  158. }
  159. internal Rect CalculatePostRenderPixelRect(float cameraAspect, int screenWidth, int screenHeight)
  160. {
  161. // This VP is used when the internal temp RT is blitted back to screen.
  162. Rect pixelRect = new Rect();
  163. if (useStretchFill)
  164. {
  165. // stretch (fit either width or height)
  166. float screenAspect = (float)screenWidth / screenHeight;
  167. if (screenAspect > cameraAspect)
  168. {
  169. pixelRect.height = screenHeight;
  170. pixelRect.width = screenHeight * cameraAspect;
  171. pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
  172. pixelRect.y = 0;
  173. }
  174. else
  175. {
  176. pixelRect.width = screenWidth;
  177. pixelRect.height = screenWidth / cameraAspect;
  178. pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
  179. pixelRect.x = 0;
  180. }
  181. }
  182. else
  183. {
  184. // center
  185. pixelRect.height = zoom * offscreenRTHeight;
  186. pixelRect.width = zoom * offscreenRTWidth;
  187. pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
  188. pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
  189. }
  190. return pixelRect;
  191. }
  192. // Find a pixel-perfect orthographic size as close to targetOrthoSize as possible.
  193. internal float CorrectCinemachineOrthoSize(float targetOrthoSize)
  194. {
  195. float correctedOrthoSize;
  196. if (m_Component.upscaleRT)
  197. {
  198. cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(orthoSize / targetOrthoSize));
  199. correctedOrthoSize = orthoSize / cinemachineVCamZoom;
  200. }
  201. else
  202. {
  203. cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(zoom * orthoSize / targetOrthoSize));
  204. correctedOrthoSize = zoom * orthoSize / cinemachineVCamZoom;
  205. }
  206. // In this case the actual zoom level is cinemachineVCamZoom instead of zoom.
  207. if (!m_Component.upscaleRT && !m_Component.pixelSnapping)
  208. unitsPerPixel = 1.0f / (cinemachineVCamZoom * m_Component.assetsPPU);
  209. return correctedOrthoSize;
  210. }
  211. }
  212. }