SHARE
TWEET

CRT-phosphorlut.shader

a guest Mar 29th, 2013 184 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--
  3.     CRT shader with phosphorLUT
  4.  
  5.     Copyright (C) 2010-2012 cgwg, Themaister and DOLLS (phosphorLUT modification by hunterk)
  6.  
  7.     This program is free software; you can redistribute it and/or modify it
  8.     under the terms of the GNU General Public License as published by the Free
  9.     Software Foundation; either version 2 of the License, or (at your option)
  10.     any later version.
  11.     -->
  12. <shader language="GLSL">
  13.    <texture id="phosphorLUT" file="240phoriz.png" filter="linear"/>
  14.     <vertex><![CDATA[
  15. varying float CRTgamma;
  16. varying float monitorgamma;
  17. varying vec2 overscan;
  18. varying vec2 aspect;
  19. varying float d;
  20. varying float R;
  21. varying float cornersize;
  22. varying float cornersmooth;
  23.  
  24. varying vec3 stretch;
  25. varying vec2 sinangle;
  26. varying vec2 cosangle;
  27.  
  28. uniform vec2 rubyInputSize;
  29. uniform vec2 rubyTextureSize;
  30. uniform vec2 rubyOutputSize;
  31.  
  32. varying vec2 texCoord;
  33. varying vec2 one;
  34. varying float mod_factor;
  35.  
  36. #define FIX(c) max(abs(c), 1e-5);
  37.  
  38. float intersect(vec2 xy)
  39. {
  40.   float A = dot(xy,xy)+d*d;
  41.   float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
  42.   float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
  43.   return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
  44. }
  45.  
  46. vec2 bkwtrans(vec2 xy)
  47. {
  48.   float c = intersect(xy);
  49.   vec2 point = vec2(c)*xy;
  50.   point -= vec2(-R)*sinangle;
  51.   point /= vec2(R);
  52.   vec2 tang = sinangle/cosangle;
  53.   vec2 poc = point/cosangle;
  54.   float A = dot(tang,tang)+1.0;
  55.   float B = -2.0*dot(poc,tang);
  56.   float C = dot(poc,poc)-1.0;
  57.   float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
  58.   vec2 uv = (point-a*sinangle)/cosangle;
  59.   float r = R*acos(a);
  60.   return uv*r/sin(r/R);
  61. }
  62.  
  63. vec2 fwtrans(vec2 uv)
  64. {
  65.   float r = FIX(sqrt(dot(uv,uv)));
  66.   uv *= sin(r/R)/r;
  67.   float x = 1.0-cos(r/R);
  68.   float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle);
  69.   return d*(uv*cosangle-x*sinangle)/D;
  70. }
  71.  
  72. vec3 maxscale()
  73. {
  74.   vec2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y));
  75.   vec2 a = vec2(0.5,0.5)*aspect;
  76.   vec2 lo = vec2(fwtrans(vec2(-a.x,c.y)).x,
  77.          fwtrans(vec2(c.x,-a.y)).y)/aspect;
  78.   vec2 hi = vec2(fwtrans(vec2(+a.x,c.y)).x,
  79.          fwtrans(vec2(c.x,+a.y)).y)/aspect;
  80.   return vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));
  81. }
  82.  
  83.  
  84. void main()
  85. {
  86.  
  87.   // START of parameters
  88.  
  89.   // gamma of simulated CRT
  90.   CRTgamma = 2.4;
  91.   // gamma of display monitor (typically 2.2 is correct)
  92.   monitorgamma = 2.2;
  93.   // overscan (e.g. 1.02 for 2% overscan)
  94.   overscan = vec2(1.00,1.00);
  95.   // aspect ratio
  96.   aspect = vec2(1.0, 0.75);
  97.   // lengths are measured in units of (approximately) the width of the monitor
  98.   // simulated distance from viewer to monitor
  99.   d = 2.0;
  100.   // radius of curvature
  101.   R = 1.5;
  102.   // tilt angle in radians
  103.   // (behavior might be a bit wrong if both components are nonzero)
  104.   const vec2 angle = vec2(0.0,-0.15);
  105.   // size of curved corners
  106.   cornersize = 0.001;
  107.   // border smoothness parameter
  108.   // decrease if borders are too aliased
  109.   cornersmooth = 1000.0;
  110.  
  111.   // END of parameters
  112.  
  113.   // Do the standard vertex processing.
  114.   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  115.  
  116.   // Precalculate a bunch of useful values we'll need in the fragment
  117.   // shader.
  118.   sinangle = sin(angle);
  119.   cosangle = cos(angle);
  120.   stretch = maxscale();
  121.  
  122.   // Texture coords.
  123.   texCoord = gl_MultiTexCoord0.xy;
  124.  
  125.   // Find the LUT coordinates
  126.          gl_TexCoord[1].xy = gl_MultiTexCoord1.xy;
  127.  
  128.   // The size of one texel, in texture-coordinates.
  129.   one = 1.0 / rubyTextureSize;
  130.  
  131.   // Resulting X pixel-coordinate of the pixel we're drawing.
  132.   mod_factor = texCoord.x * rubyTextureSize.x * rubyOutputSize.x / rubyInputSize.x;            
  133. }
  134.     ]]></vertex>
  135.     <fragment outscale="2.0"><![CDATA[
  136. // Comment the next line to disable interpolation in linear gamma (and gain speed).
  137. //#define LINEAR_PROCESSING
  138.  
  139. // Enable screen curvature.
  140. //#define CURVATURE
  141.  
  142. // Enable 3x oversampling of the beam profile
  143. #define OVERSAMPLE
  144.  
  145. // Use the older, purely gaussian beam profile
  146. //#define USEGAUSSIAN
  147.  
  148. // Macros.
  149. #define FIX(c) max(abs(c), 1e-5);
  150. #define PI 3.141592653589
  151.  
  152. #ifdef LINEAR_PROCESSING
  153. #       define TEX2D(c) pow(texture2D(rubyTexture, (c)), vec4(CRTgamma))
  154. #else
  155. #       define TEX2D(c) texture2D(rubyTexture, (c))
  156. #endif
  157.  
  158. uniform sampler2D rubyTexture;
  159. uniform vec2 rubyInputSize;
  160. uniform vec2 rubyTextureSize;
  161. uniform float brightness;
  162.  
  163. // Identify LUT texture
  164.       uniform sampler2D phosphorLUT;
  165.  
  166. varying vec2 texCoord;
  167. varying vec2 one;
  168. varying float mod_factor;
  169.  
  170. varying float CRTgamma;
  171. varying float monitorgamma;
  172.  
  173. varying vec2 overscan;
  174. varying vec2 aspect;
  175.  
  176. varying float d;
  177. varying float R;
  178.  
  179. varying float cornersize;
  180. varying float cornersmooth;
  181.  
  182. varying vec3 stretch;
  183. varying vec2 sinangle;
  184. varying vec2 cosangle;
  185.  
  186. float intersect(vec2 xy)
  187. {
  188.   float A = dot(xy,xy)+d*d;
  189.   float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
  190.   float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
  191.   return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
  192. }
  193.  
  194. vec2 bkwtrans(vec2 xy)
  195. {
  196.   float c = intersect(xy);
  197.   vec2 point = vec2(c)*xy;
  198.   point -= vec2(-R)*sinangle;
  199.   point /= vec2(R);
  200.   vec2 tang = sinangle/cosangle;
  201.   vec2 poc = point/cosangle;
  202.   float A = dot(tang,tang)+1.0;
  203.   float B = -2.0*dot(poc,tang);
  204.   float C = dot(poc,poc)-1.0;
  205.   float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
  206.   vec2 uv = (point-a*sinangle)/cosangle;
  207.   float r = FIX(R*acos(a));
  208.   return uv*r/sin(r/R);
  209. }
  210.  
  211. vec2 transform(vec2 coord)
  212. {
  213.   coord *= rubyTextureSize / rubyInputSize;
  214.   coord = (coord-vec2(0.5))*aspect*stretch.z+stretch.xy;
  215.   return (bkwtrans(coord)/overscan/aspect+vec2(0.5)) * rubyInputSize / rubyTextureSize;
  216. }
  217.  
  218. float corner(vec2 coord)
  219. {
  220.   coord *= rubyTextureSize / rubyInputSize;
  221.   coord = (coord - vec2(0.5)) * overscan + vec2(0.5);
  222.   coord = min(coord, vec2(1.0)-coord) * aspect;
  223.   vec2 cdist = vec2(cornersize);
  224.   coord = (cdist - min(coord,cdist));
  225.   float dist = sqrt(dot(coord,coord));
  226.   return clamp((cdist.x-dist)*cornersmooth,0.0, 1.0);
  227. }
  228.  
  229. // Calculate the influence of a scanline on the current pixel.
  230. //
  231. // 'distance' is the distance in texture coordinates from the current
  232. // pixel to the scanline in question.
  233. // 'color' is the colour of the scanline at the horizontal location of
  234. // the current pixel.
  235. vec4 scanlineWeights(float distance, vec4 color)
  236. {
  237.   // "wid" controls the width of the scanline beam, for each RGB channel
  238.   // The "weights" lines basically specify the formula that gives
  239.   // you the profile of the beam, i.e. the intensity as
  240.   // a function of distance from the vertical center of the
  241.   // scanline. In this case, it is gaussian if width=2, and
  242.   // becomes nongaussian for larger widths. Ideally this should
  243.   // be normalized so that the integral across the beam is
  244.   // independent of its width. That is, for a narrower beam
  245.   // "weights" should have a higher peak at the center of the
  246.   // scanline than for a wider beam.
  247. #ifdef USEGAUSSIAN
  248.   vec4 wid = 0.3 + 0.1 * pow(color, vec4(3.0));
  249.   vec4 weights = vec4(distance / wid);
  250.   return 0.4 * exp(-weights * weights) / wid;
  251. #else
  252.   vec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0));
  253.   vec4 weights = vec4(distance / 0.3);
  254.   return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
  255. #endif
  256. }
  257.  
  258. void main()
  259. {
  260.   // Here's a helpful diagram to keep in mind while trying to
  261.   // understand the code:
  262.   //
  263.   //  |      |      |      |      |
  264.   // -------------------------------
  265.   //  |      |      |      |      |
  266.   //  |  01  |  11  |  21  |  31  | <-- current scanline
  267.   //  |      | @    |      |      |
  268.   // -------------------------------
  269.   //  |      |      |      |      |
  270.   //  |  02  |  12  |  22  |  32  | <-- next scanline
  271.   //  |      |      |      |      |
  272.   // -------------------------------
  273.   //  |      |      |      |      |
  274.   //
  275.   // Each character-cell represents a pixel on the output
  276.   // surface, "@" represents the current pixel (always somewhere
  277.   // in the bottom half of the current scan-line, or the top-half
  278.   // of the next scanline). The grid of lines represents the
  279.   // edges of the texels of the underlying texture.
  280.  
  281.   // Texture coordinates of the texel containing the active pixel.
  282. #ifdef CURVATURE
  283.   vec2 xy = transform(texCoord);
  284. #else
  285.   vec2 xy = texCoord;
  286. #endif
  287.   float cval = corner(xy);
  288.  
  289.   // Of all the pixels that are mapped onto the texel we are
  290.   // currently rendering, which pixel are we currently rendering?
  291.   vec2 ratio_scale = xy * rubyTextureSize - vec2(0.5);
  292. #ifdef OVERSAMPLE
  293.   float filter = fwidth(ratio_scale.y);
  294. #endif
  295.   vec2 uv_ratio = fract(ratio_scale);
  296.  
  297.   // Snap to the center of the underlying texel.
  298.   xy = (floor(ratio_scale) + vec2(0.5)) / rubyTextureSize;
  299.  
  300.   // Calculate Lanczos scaling coefficients describing the effect
  301.   // of various neighbour texels in a scanline on the current
  302.   // pixel.
  303.   vec4 coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
  304.  
  305.   // Prevent division by zero.
  306.   coeffs = FIX(coeffs);
  307.  
  308.   // Lanczos2 kernel.
  309.   coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
  310.  
  311.   // Normalize.
  312.   coeffs /= dot(coeffs, vec4(1.0));
  313.  
  314.   // Calculate the effective colour of the current and next
  315.   // scanlines at the horizontal location of the current pixel,
  316.   // using the Lanczos coefficients above.
  317.   vec4 col  = clamp(mat4(
  318.              TEX2D(xy + vec2(-one.x, 0.0)),
  319.              TEX2D(xy),
  320.              TEX2D(xy + vec2(one.x, 0.0)),
  321.              TEX2D(xy + vec2(2.0 * one.x, 0.0))) * coeffs,
  322.             0.0, 1.0);
  323.   vec4 col2 = clamp(mat4(
  324.              TEX2D(xy + vec2(-one.x, one.y)),
  325.              TEX2D(xy + vec2(0.0, one.y)),
  326.              TEX2D(xy + one),
  327.              TEX2D(xy + vec2(2.0 * one.x, one.y))) * coeffs,
  328.             0.0, 1.0);
  329.  
  330. #ifndef LINEAR_PROCESSING
  331.   col  = pow(col , vec4(CRTgamma));
  332.   col2 = pow(col2, vec4(CRTgamma));
  333. #endif
  334.  
  335.   // Calculate the influence of the current and next scanlines on
  336.   // the current pixel.
  337.   vec4 weights  = scanlineWeights(uv_ratio.y, col);
  338.   vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
  339. #ifdef OVERSAMPLE
  340.   uv_ratio.y =uv_ratio.y+1.0/3.0*filter;
  341.   weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;
  342.   weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;
  343.   uv_ratio.y =uv_ratio.y-2.0/3.0*filter;
  344.   weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;
  345.   weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;
  346. #endif
  347.   vec3 mul_res  = (col * weights + col2 * weights2).rgb * vec3(cval);
  348.  
  349.  
  350.   // Convert the image gamma for display on our output device.
  351.   mul_res = pow(mul_res, vec3(1.0 / monitorgamma));
  352.  
  353.         // Identify the LUT and screen textures
  354.          float brightness = 1.6;
  355.          vec4 inverse = 1 - (brightness * texture2D(rubyTexture, texCoord));
  356.          vec4 screen = texture2D(phosphorLUT, gl_TexCoord[1].xy);
  357.          
  358.             vec4 final = screen - inverse;
  359.  
  360.   // Color the texel.
  361.     gl_FragColor = screen - (1.0 - (brightness * vec4(mul_res, 1.0)));
  362.  
  363. }
  364.     ]]></fragment>
  365. </shader>
RAW Paste Data
Top