123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- using System;
- namespace UnityEngine.Experimental.Rendering.Universal
- {
- internal interface IPixelPerfectCamera
- {
- int assetsPPU { get; set; }
- int refResolutionX { get; set; }
- int refResolutionY { get; set; }
- bool upscaleRT { get; set; }
- bool pixelSnapping { get; set; }
- bool cropFrameX { get; set; }
- bool cropFrameY { get; set; }
- bool stretchFill { get; set; }
- }
- [Serializable]
- internal class PixelPerfectCameraInternal : ISerializationCallbackReceiver
- {
- // Case 1061634:
- // In order for this class to survive hot reloading, we need to make the fields serializable.
- // Unity can't serialize an interface object, but does properly serialize UnityEngine.Object.
- // So we cast the reference to PixelPerfectCamera (which inherits UnityEngine.Object)
- // before serialization happens, and restore the interface reference after deserialization.
- [NonSerialized]
- IPixelPerfectCamera m_Component;
- PixelPerfectCamera m_SerializableComponent;
- internal float originalOrthoSize;
- internal bool hasPostProcessLayer;
- internal bool cropFrameXAndY = false;
- internal bool cropFrameXOrY = false;
- internal bool useStretchFill = false;
- internal int zoom = 1;
- internal bool useOffscreenRT = false;
- internal int offscreenRTWidth = 0;
- internal int offscreenRTHeight = 0;
- internal Rect pixelRect = Rect.zero;
- internal float orthoSize = 1.0f;
- internal float unitsPerPixel = 0.0f;
- internal int cinemachineVCamZoom = 1;
- internal PixelPerfectCameraInternal(IPixelPerfectCamera component)
- {
- m_Component = component;
- }
- public void OnBeforeSerialize()
- {
- m_SerializableComponent = m_Component as PixelPerfectCamera;
- }
- public void OnAfterDeserialize()
- {
- if (m_SerializableComponent != null)
- m_Component = m_SerializableComponent;
- }
- internal void CalculateCameraProperties(int screenWidth, int screenHeight)
- {
- int assetsPPU = m_Component.assetsPPU;
- int refResolutionX = m_Component.refResolutionX;
- int refResolutionY = m_Component.refResolutionY;
- bool upscaleRT = m_Component.upscaleRT;
- bool pixelSnapping = m_Component.pixelSnapping;
- bool cropFrameX = m_Component.cropFrameX;
- bool cropFrameY = m_Component.cropFrameY;
- bool stretchFill = m_Component.stretchFill;
- cropFrameXAndY = cropFrameY && cropFrameX;
- cropFrameXOrY = cropFrameY || cropFrameX;
- useStretchFill = cropFrameXAndY && stretchFill;
- // zoom level (PPU scale)
- int verticalZoom = screenHeight / refResolutionY;
- int horizontalZoom = screenWidth / refResolutionX;
- zoom = Math.Max(1, Math.Min(verticalZoom, horizontalZoom));
- // off-screen RT
- useOffscreenRT = false;
- offscreenRTWidth = 0;
- offscreenRTHeight = 0;
- if (cropFrameXOrY)
- {
- useOffscreenRT = true;
- if (!upscaleRT)
- {
- if (cropFrameXAndY)
- {
- offscreenRTWidth = zoom * refResolutionX;
- offscreenRTHeight = zoom * refResolutionY;
- }
- else if (cropFrameY)
- {
- offscreenRTWidth = screenWidth;
- offscreenRTHeight = zoom * refResolutionY;
- }
- else // crop frame X
- {
- offscreenRTWidth = zoom * refResolutionX;
- offscreenRTHeight = screenHeight;
- }
- }
- else
- {
- if (cropFrameXAndY)
- {
- offscreenRTWidth = refResolutionX;
- offscreenRTHeight = refResolutionY;
- }
- else if (cropFrameY)
- {
- offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
- offscreenRTHeight = refResolutionY;
- }
- else // crop frame X
- {
- offscreenRTWidth = refResolutionX;
- offscreenRTHeight = screenHeight / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
- }
- }
- }
- else if (upscaleRT && zoom > 1)
- {
- useOffscreenRT = true;
- offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
- offscreenRTHeight = screenHeight / zoom / 2 * 2;
- }
- // viewport
- if (useOffscreenRT)
- {
- // When we ask the render pipeline to create the offscreen RT for us, the size of the RT is determined by VP size.
- // That's why we set the VP size to be (m_OffscreenRTWidth, m_OffscreenRTHeight) here.
- pixelRect = new Rect(0.0f, 0.0f, offscreenRTWidth, offscreenRTHeight);
- }
- else
- pixelRect = Rect.zero;
- // orthographic size
- if (cropFrameY)
- orthoSize = (refResolutionY * 0.5f) / assetsPPU;
- else if (cropFrameX)
- {
- float aspect = (pixelRect == Rect.zero) ? (float)screenWidth / screenHeight : pixelRect.width / pixelRect.height;
- orthoSize = ((refResolutionX / aspect) * 0.5f) / assetsPPU;
- }
- else if (upscaleRT && zoom > 1)
- orthoSize = (offscreenRTHeight * 0.5f) / assetsPPU;
- else
- {
- float pixelHeight = (pixelRect == Rect.zero) ? screenHeight : pixelRect.height;
- orthoSize = (pixelHeight * 0.5f) / (zoom * assetsPPU);
- }
- // Camera pixel grid spacing
- if (upscaleRT || (!upscaleRT && pixelSnapping))
- unitsPerPixel = 1.0f / assetsPPU;
- else
- unitsPerPixel = 1.0f / (zoom * assetsPPU);
- }
- internal Rect CalculateFinalBlitPixelRect(int screenWidth, int screenHeight)
- {
- // This VP is used when the internal temp RT is blitted back to screen.
- Rect pixelRect = new Rect();
- if (useStretchFill)
- {
- // stretch (fit either width or height)
- float screenAspect = (float)screenWidth / screenHeight;
- float cameraAspect = (float)m_Component.refResolutionX / m_Component.refResolutionY;
- if (screenAspect > cameraAspect)
- {
- pixelRect.height = screenHeight;
- pixelRect.width = screenHeight * cameraAspect;
- pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
- pixelRect.y = 0;
- }
- else
- {
- pixelRect.width = screenWidth;
- pixelRect.height = screenWidth / cameraAspect;
- pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
- pixelRect.x = 0;
- }
- }
- else
- {
- // center
- if (m_Component.upscaleRT)
- {
- pixelRect.height = zoom * offscreenRTHeight;
- pixelRect.width = zoom * offscreenRTWidth;
- }
- else
- {
- pixelRect.height = offscreenRTHeight;
- pixelRect.width = offscreenRTWidth;
- }
- pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
- pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
- }
- return pixelRect;
- }
- // Find a pixel-perfect orthographic size as close to targetOrthoSize as possible.
- internal float CorrectCinemachineOrthoSize(float targetOrthoSize)
- {
- float correctedOrthoSize;
- if (m_Component.upscaleRT)
- {
- cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(orthoSize / targetOrthoSize));
- correctedOrthoSize = orthoSize / cinemachineVCamZoom;
- }
- else
- {
- cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(zoom * orthoSize / targetOrthoSize));
- correctedOrthoSize = zoom * orthoSize / cinemachineVCamZoom;
- }
- // In this case the actual zoom level is cinemachineVCamZoom instead of zoom.
- if (!m_Component.upscaleRT && !m_Component.pixelSnapping)
- unitsPerPixel = 1.0f / (cinemachineVCamZoom * m_Component.assetsPPU);
- return correctedOrthoSize;
- }
- }
- }
|