Advertisement
Guest User

CRT-phosphorlut.shader

a guest
Mar 29th, 2013
706
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.00 KB | None | 0 0
  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>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement