Advertisement
Guest User

Untitled

a guest
Jun 25th, 2019
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.29 KB | None | 0 0
  1. #define DECODE_FILTER_TAPS_8
  2. // #define DECODE_FILTER_TAPS_24
  3.  
  4. namespace JetFistGames.RetroTVFX
  5. {
  6.    
  7.     using UnityEngine;
  8.     using UnityStandardAssets.ImageEffects;
  9.  
  10.     public enum VideoType
  11.     {
  12.         /// <summary>
  13.         /// RF takes YIQ and muxes luma and chroma into a single signal (actually, real RF also includes audio)
  14.         /// Real RF then modulates it with a radio wave carrier. It's subject to extra blurring and noise
  15.         /// </summary>
  16.         RF,
  17.  
  18.         /// <summary>
  19.         /// Composite takes YIQ and muxes luma and chroma into a single signal
  20.         /// Slightly less color blurring than RF and no noise, but still fairly blurry
  21.         /// </summary>
  22.         Composite,
  23.  
  24.         /// <summary>
  25.         /// S-Video takes YIQ and separates it into two signals - a luma signal, and a muxed chroma signal
  26.         /// Closer to Component, but with some color bleeding still present
  27.         /// </summary>
  28.         SVideo,
  29.  
  30.         /// <summary>
  31.         /// Component takes YIQ information and sends it over three different cables.
  32.         /// Since there's no signal multiplexing, the output is very clean.
  33.         /// </summary>
  34.         Component,
  35.  
  36.         /// <summary>
  37.         /// VGA (and SCART) can transmit pure un-muxed RGB color.
  38.         /// This will result in image quality nearly identical to the input. Used in arcade games.
  39.         /// </summary>
  40.         VGA,
  41.  
  42.         /// <summary>
  43.         /// A more efficient version of VGA/SCART. Just blits directly to the screen.
  44.         /// </summary>
  45.         VGAFast,
  46.     }
  47.  
  48.     [ExecuteInEditMode]
  49.     public class CRTEffect : ImageEffectBase
  50.     {
  51.         private const int PASS_COMPOSITE_ENCODE = 0;
  52.         private const int PASS_COMPOSITE_DECODE = 1;
  53.         private const int PASS_COMPOSITE_FINAL = 2;
  54.  
  55.         private const int PASS_VGA = 4;
  56.         private const int PASS_COMPONENT = 5;
  57.  
  58.         private const int PASS_SVIDEO_ENCODE = 6;
  59.         private const int PASS_SVIDEO_DECODE = 7;
  60.  
  61.         private const int PASS_TV_OVERLAY = 3;
  62.  
  63.         [Header("Shader Properties")]
  64.  
  65.         [Tooltip("Which style of video to use")]
  66.         public VideoType VideoMode = VideoType.Composite;
  67.  
  68.         public int DisplaySizeX = 960;
  69.         public int DisplaySizeY = 480;
  70.  
  71.         public bool StretchToDisplay = true;
  72.  
  73.         public float AspectRatio = 1.33f;
  74.  
  75.         [Tooltip("Apply curvature to display")]
  76.         public bool EnableTVCurvature = false;
  77.  
  78.         [Range(0f, 1f)]
  79.         public float Curvature = 0f;
  80.  
  81.         [Tooltip("Overlay image applied (before curvature)")]
  82.         public Texture2D TVOverlay;
  83.  
  84.         public bool EnablePixelMask = true;
  85.         public Texture2D PixelMaskTexture;
  86.         public int MaskRepeatX = 160;
  87.         public int MaskRepeatY = 90;
  88.  
  89.         [Range(1f, 2f)]
  90.         public float PixelMaskBrightness = 1f;
  91.  
  92.         public Vector2 IQOffset = Vector2.zero;
  93.         public Vector2 IQScale = Vector2.one;
  94.  
  95.         [Range(0f, 2f)]
  96.         public float RFNoise = 0.25f;
  97.  
  98.         [Range(0f, 4f)]
  99.         public float LumaSharpen = 0f;
  100.  
  101.         public bool QuantizeRGB = false;
  102.  
  103.         [Range(2, 8)]
  104.         public int RBits = 8;
  105.  
  106.         [Range(2, 8)]
  107.         public int GBits = 8;
  108.  
  109.         [Range(2, 8)]
  110.         public int BBits = 8;
  111.  
  112.         public bool EnableBurstCountAnimation = true;
  113.         public bool AntiFlicker = false;
  114.  
  115.         public bool EnableRollingFlicker = false;
  116.  
  117.         [Range(0f, 1f)]
  118.         public float RollingFlickerFactor = 0.25f;
  119.  
  120.         [Range(0f, 2f)]
  121.         public float RollingVSyncTime = 1f;
  122.  
  123.         private RenderTexture compositeTemp;
  124.  
  125.         private int frameCount = 0;
  126.  
  127.         private float flickerOffset = 0f;
  128.  
  129.         private bool antiFlickerEnabled = false;
  130.         private bool rollingFlickerEnabled = false;
  131.         private bool pixelMaskEnabled = false;
  132.         private bool tvCurvatureEnabled = false;
  133.         private bool quantizeRGBEnabled = false;
  134.         private bool rfEnabled = false;
  135.  
  136.         #region Decode filter kernel
  137. #if DECODE_FILTER_TAPS_8
  138.         private float[] lumaFilter =
  139.         {
  140.            -0.0020f, -0.0009f, 0.0038f, 0.0178f, 0.0445f,
  141.             0.0817f, 0.1214f, 0.1519f, 0.1634f
  142.         };
  143.  
  144.         private float[] chromaFilter =
  145.         {
  146.             0.0046f, 0.0082f, 0.0182f, 0.0353f, 0.0501f,
  147.             0.0832f, 0.1062f, 0.1222f, 0.1280f
  148.         };
  149. #else
  150.         private float[] lumaFilter = new float[]
  151.         {
  152.             -0.000012020f,
  153.             -0.000022146f,
  154.             -0.000013155f,
  155.             -0.000012020f,
  156.             -0.000049979f,
  157.             -0.000113940f,
  158.             -0.000122150f,
  159.             -0.000005612f,
  160.             0.000170516f,
  161.             0.000237199f,
  162.             0.000169640f,
  163.             0.000285688f,
  164.             0.000984574f,
  165.             0.002018683f,
  166.             0.002002275f,
  167.             -0.000909882f,
  168.             -0.007049081f,
  169.             -0.013222860f,
  170.             -0.012606931f,
  171.             0.002460860f,
  172.             0.035868225f,
  173.             0.084016453f,
  174.             0.135563500f,
  175.             0.175261268f,
  176.             0.190176552f
  177.         };
  178.  
  179.         private float[] chromaFilter = new float[]
  180.         {
  181.             -0.000118847f,
  182.             -0.000271306f,
  183.             -0.000502642f,
  184.             -0.000930833f,
  185.             -0.001451013f,
  186.             -0.002064744f,
  187.             -0.002700432f,
  188.             -0.003241276f,
  189.             -0.003524948f,
  190.             -0.003350284f,
  191.             -0.002491729f,
  192.             -0.000721149f,
  193.             0.002164659f,
  194.             0.006313635f,
  195.             0.011789103f,
  196.             0.018545660f,
  197.             0.026414396f,
  198.             0.035100710f,
  199.             0.044196567f,
  200.             0.053207202f,
  201.             0.061590275f,
  202.             0.068803602f,
  203.             0.074356193f,
  204.             0.077856564f,
  205.             0.079052396f
  206.         };
  207. #endif
  208.         #endregion
  209.  
  210.         private Matrix4x4 rgb2yiq_mat = Matrix4x4.identity;
  211.         private Matrix4x4 yiq2rgb_mat = Matrix4x4.identity;
  212.  
  213.         override protected void Start()
  214.         {
  215.             base.Start();
  216.         }
  217.  
  218.         override protected void OnDisable()
  219.         {
  220.             base.OnDisable();
  221.             DestroyImmediate(compositeTemp);
  222.         }
  223.  
  224.         void LateUpdate()
  225.         {
  226.             if (EnableBurstCountAnimation)
  227.             {
  228.                 this.frameCount++;
  229.                 this.frameCount %= 3;
  230.             }
  231.  
  232.             if (EnableRollingFlicker)
  233.             {
  234.                 this.flickerOffset += this.RollingVSyncTime;
  235.             }
  236.         }
  237.  
  238.         void ensureResources()
  239.         {
  240.             if (this.rgb2yiq_mat == Matrix4x4.identity)
  241.             {
  242.                 this.rgb2yiq_mat.SetRow(0, new Vector4(0.299f, 0.587f, 0.114f, 0f));
  243.                 this.rgb2yiq_mat.SetRow(1, new Vector4(0.596f, -0.275f, -0.321f, 0f));
  244.                 this.rgb2yiq_mat.SetRow(2, new Vector4(0.221f, -0.523f, 0.311f, 0f));
  245.             }
  246.  
  247.             if (this.yiq2rgb_mat == Matrix4x4.identity)
  248.             {
  249.                 this.yiq2rgb_mat.SetRow(0, new Vector4(1f, 0.956f, 0.621f, 0f));
  250.                 this.yiq2rgb_mat.SetRow(1, new Vector4(1f, -0.272f, -0.647f, 0f));
  251.                 this.yiq2rgb_mat.SetRow(2, new Vector4(1f, -1.106f, 1.703f, 0f));
  252.             }
  253.  
  254.             material.SetMatrix("_RGB2YIQ_MAT", this.rgb2yiq_mat);
  255.             material.SetMatrix("_YIQ2RGB_MAT", this.yiq2rgb_mat);
  256.  
  257.             material.SetTexture("_OverlayImg", this.TVOverlay);
  258.            
  259.             material.SetFloatArray("_LumaFilter", this.lumaFilter);
  260.             material.SetFloatArray("_ChromaFilter", this.chromaFilter);
  261.         }
  262.  
  263.         void OnRenderImage(RenderTexture src, RenderTexture dest)
  264.         {
  265.             ensureResources();
  266.  
  267.             setKeyword("ANTI_FLICKER", this.AntiFlicker, ref this.antiFlickerEnabled);
  268.             setKeyword("ROLLING_FLICKER", this.EnableRollingFlicker, ref this.rollingFlickerEnabled);
  269.             setKeyword("PIXEL_MASK", this.EnablePixelMask, ref this.pixelMaskEnabled);
  270.             setKeyword("USE_TV_CURVATURE", this.EnableTVCurvature, ref this.tvCurvatureEnabled);
  271.             setKeyword("QUANTIZE_RGB", this.QuantizeRGB, ref this.quantizeRGBEnabled);
  272.             setKeyword("RF_SIGNAL", this.VideoMode == VideoType.RF, ref this.rfEnabled);
  273.  
  274.             if (compositeTemp == null || compositeTemp.width != DisplaySizeX || compositeTemp.height != DisplaySizeY)
  275.             {
  276.                 DestroyImmediate(compositeTemp);
  277.                 compositeTemp = new RenderTexture(DisplaySizeX, DisplaySizeY, src.depth, RenderTextureFormat.ARGBHalf);
  278.             }
  279.  
  280.             if (QuantizeRGB)
  281.             {
  282.                 Vector4 quantize = new Vector4(Mathf.Pow(2f, RBits), Mathf.Pow(2f, GBits), Mathf.Pow(2f, BBits), 1f);
  283.                 Vector4 oneOverQuantize = new Vector4(1f / quantize.x, 1f / quantize.y, 1f / quantize.z, 1f);
  284.  
  285.                 material.SetVector("_QuantizeRGB", quantize);
  286.                 material.SetVector("_OneOverQuantizeRGB", oneOverQuantize);
  287.             }
  288.  
  289.             material.SetFloat("_Realtime", Time.realtimeSinceStartup);
  290.  
  291.             material.SetVector("_IQOffset", new Vector4(IQScale.x, IQScale.y, IQOffset.x, IQOffset.y));
  292.             material.SetMatrix("_RGB2YIQ_MAT", this.rgb2yiq_mat);
  293.             material.SetMatrix("_YIQ2RGB_MAT", this.yiq2rgb_mat);
  294.  
  295.             material.SetFloat("_RFNoise", this.RFNoise);
  296.             material.SetFloat("_LumaSharpen", this.LumaSharpen);
  297.  
  298.             material.SetInt("_Framecount", -this.frameCount);
  299.             material.SetVector("_ScreenSize", new Vector4(DisplaySizeX, DisplaySizeY, 1f / DisplaySizeX, 1f / DisplaySizeY));
  300.  
  301.             material.SetFloat("_RollingFlickerAmount", this.RollingFlickerFactor);
  302.             material.SetVector("_FlickerOffs", new Vector4(this.flickerOffset, this.flickerOffset + RollingVSyncTime, 0f, 0f));
  303.  
  304.             material.SetVector("_PixelMaskScale", new Vector4(MaskRepeatX, MaskRepeatY));
  305.             material.SetTexture("_PixelMask", PixelMaskTexture);
  306.             material.SetFloat("_Brightness", PixelMaskBrightness);
  307.  
  308.             material.SetFloat("_TVCurvature", Curvature);
  309.            
  310.  
  311.             RenderTexture pass1 = RenderTexture.GetTemporary(DisplaySizeX, DisplaySizeY, src.depth, RenderTextureFormat.ARGBHalf);
  312.             //pass1.filterMode = FilterMode.Point;
  313.             RenderTexture pass2 = RenderTexture.GetTemporary(DisplaySizeX, DisplaySizeY, src.depth, RenderTextureFormat.ARGBHalf);
  314.             //pass2.filterMode = FilterMode.Point;
  315.  
  316.             RenderTexture lastComposite = RenderTexture.GetTemporary(DisplaySizeX, DisplaySizeY, src.depth, RenderTextureFormat.ARGBHalf);
  317.  
  318.             RenderTexture final = pass1;
  319.  
  320.             if (this.VideoMode == VideoType.Composite || this.VideoMode == VideoType.RF)
  321.             {
  322.                 Graphics.Blit(src, pass1);
  323.  
  324.                 Graphics.Blit(pass1, pass2, material, PASS_COMPOSITE_ENCODE);
  325.  
  326.                 // pass last frame's signal and save current frame's signal
  327.                 Graphics.Blit(compositeTemp, lastComposite);
  328.                 Graphics.Blit(pass2, compositeTemp);
  329.                 material.SetTexture("_LastCompositeTex", lastComposite);
  330.                
  331.                 Graphics.Blit(pass2, pass1, material, PASS_COMPOSITE_DECODE);
  332.                 Graphics.Blit(pass1, pass2, material, PASS_COMPOSITE_FINAL);
  333.  
  334.                 final = pass2;
  335.             }
  336.             else if (this.VideoMode == VideoType.SVideo)
  337.             {
  338.                 Graphics.Blit(src, pass1);
  339.  
  340.                 Graphics.Blit(pass1, pass2, material, PASS_SVIDEO_ENCODE);
  341.  
  342.                 // pass last frame's signal and save current frame's signal
  343.                 Graphics.Blit(compositeTemp, lastComposite);
  344.                 Graphics.Blit(pass2, compositeTemp);
  345.                 material.SetTexture("_LastCompositeTex", lastComposite);
  346.  
  347.                 Graphics.Blit(pass2, pass1, material, PASS_SVIDEO_DECODE);
  348.             }
  349.             else if (this.VideoMode == VideoType.VGA)
  350.             {
  351.                 Graphics.Blit(src, pass1, material, PASS_VGA);
  352.             }
  353.             else if (this.VideoMode == VideoType.VGAFast)
  354.             {
  355.                 final = src;
  356.             }
  357.             else if (this.VideoMode == VideoType.Component)
  358.             {
  359.                 Graphics.Blit(src, pass1, material, PASS_COMPONENT);
  360.             }
  361.  
  362.             //Graphics.Blit(final, dest, material, PASS_TV_OVERLAY);
  363.             if (StretchToDisplay)
  364.                 blitQuad(final, dest, material, PASS_TV_OVERLAY);
  365.             else
  366.             {
  367.                 float screenAspect = (float)Screen.width / (float)Screen.height;
  368.  
  369.                 if (screenAspect < AspectRatio)
  370.                 {
  371.                     // fit to screen width
  372.                     float width = 1f;
  373.                     float height = screenAspect / AspectRatio;
  374.                     float heightDiff = 1f - height;
  375.  
  376.                     blitQuad(new Rect(0f, heightDiff * 0.5f, width, height), final, dest, material, PASS_TV_OVERLAY);
  377.                 }
  378.                 else
  379.                 {
  380.                     // fit to screen height
  381.                     float height = 1f;
  382.                     float width = (1f / screenAspect) * AspectRatio;
  383.                     float widthDiff = 1f - width;
  384.  
  385.                     blitQuad(new Rect(widthDiff * 0.5f, 0f, width, height), final, dest, material, PASS_TV_OVERLAY);
  386.                 }
  387.             }
  388.  
  389.             RenderTexture.ReleaseTemporary(pass1);
  390.             RenderTexture.ReleaseTemporary(pass2);
  391.             RenderTexture.ReleaseTemporary(lastComposite);
  392.         }
  393.  
  394.         private void setKeyword(string keyword, bool enabled, ref bool keywordEnabled)
  395.         {
  396.             if (enabled != keywordEnabled)
  397.             {
  398.                 if (enabled)
  399.                     material.EnableKeyword(keyword);
  400.                 else
  401.                     material.DisableKeyword(keyword);
  402.             }
  403.  
  404.             keywordEnabled = enabled;
  405.         }
  406.  
  407.         private void blitQuad(RenderTexture src, RenderTexture dest, Material material, int pass)
  408.         {
  409.             blitQuad(new Rect(0f, 0f, 1f, 1f), src, dest, material, pass);
  410.         }
  411.  
  412.         private void blitQuad(Rect rect, RenderTexture src, RenderTexture dest, Material material, int pass)
  413.         {
  414.             GL.PushMatrix();
  415.             GL.LoadOrtho();
  416.  
  417.             RenderTexture.active = dest;
  418.             GL.Clear(true, true, Color.black);
  419.  
  420.             material.SetTexture("_MainTex", src);
  421.             material.SetPass(pass);
  422.             GL.Begin(GL.QUADS);
  423.             GL.Color(Color.white);
  424.             GL.TexCoord2(0, 0);
  425.             GL.Vertex3(rect.x, rect.y, 0.1f);
  426.  
  427.             GL.TexCoord2(1, 0);
  428.             GL.Vertex3(rect.xMax, rect.y, 0.1f);
  429.  
  430.             GL.TexCoord2(1, 1);
  431.             GL.Vertex3(rect.xMax, rect.yMax, 0.1f);
  432.  
  433.             GL.TexCoord2(0, 1);
  434.             GL.Vertex3(rect.x, rect.yMax, 0.1f);
  435.             GL.End();
  436.  
  437.             GL.PopMatrix();
  438.         }
  439.     }
  440.  
  441. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement