Advertisement
Guest User

ntsc-scanlines-phosphorlut.shader

a guest
Mar 29th, 2013
626
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.75 KB | None | 0 0
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--
  3. NTSC and scanline code
  4. Author: Themaister
  5. Gaussian Blur code
  6. Author: cgwg
  7. PhosphorLUT code
  8. Author: hunterk
  9.  
  10. This shader uses an external lookup texture (LUT) to create a shadow mask with individual RGB phosphor lenses.
  11. You can swap out the LUTs by changing the 'file' referenced in Line 16.
  12. Adjust the 'brightness' variable toward the end of the file if the LUT makes things too dark.
  13. License: GPLv3 (contains code from other GPL shaders).
  14. -->
  15. <shader language="GLSL" style="GLES2">
  16. <texture id="phosphorLUT" file="480pvert.png" filter="linear"/>
  17. <!-- 1st pass: Scale and modulate YIQ -->
  18. <vertex><![CDATA[
  19. #version 120
  20. uniform mat4 rubyMVPMatrix;
  21. attribute vec2 rubyVertexCoord;
  22. attribute vec2 rubyTexCoord;
  23. varying vec2 tex_coord;
  24.  
  25. varying vec2 pix_no;
  26. uniform vec2 rubyTextureSize;
  27. uniform vec2 rubyInputSize;
  28. uniform vec2 rubyOutputSize;
  29.  
  30. void main()
  31. {
  32. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  33. tex_coord = rubyTexCoord;
  34. pix_no = rubyTexCoord * rubyTextureSize * (rubyOutputSize / rubyInputSize);
  35. }
  36. ]]></vertex>
  37. <fragment filter="nearest" scale_x="4.0" scale_y="1.0" frame_count_mod="2" float_framebuffer="true"><![CDATA[
  38. #version 120
  39. varying vec2 tex_coord;
  40. uniform sampler2D rubyTexture;
  41. uniform int rubyFrameCount;
  42. varying vec2 pix_no;
  43.  
  44. #define PI 3.14159265
  45. #define CHROMA_MOD_FREQ (0.4 * PI)
  46. #define CHROMA_AMP 1.0
  47. #define ENCODE_GAMMA (1.0 / 2.2)
  48.  
  49. const mat3 yiq_mat = mat3(
  50. 0.2989, 0.5959, 0.2115,
  51. 0.5870, -0.2744, -0.5229,
  52. 0.1140, -0.3216, 0.3114);
  53.  
  54. vec3 rgb2yiq(vec3 col)
  55. {
  56. return yiq_mat * col;
  57. }
  58.  
  59. void main()
  60. {
  61. vec3 col = texture2D(rubyTexture, tex_coord).rgb;
  62. vec3 yiq = rgb2yiq(pow(col, vec3(ENCODE_GAMMA)));
  63.  
  64. float chroma_phase = PI * 0.6667 * (mod(pix_no.y, 3.0) + float(rubyFrameCount));
  65. float mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ;
  66.  
  67. float i_mod = CHROMA_AMP * cos(mod_phase);
  68. float q_mod = CHROMA_AMP * sin(mod_phase);
  69.  
  70. yiq = vec3(yiq.x, yiq.y * i_mod, yiq.z * q_mod);
  71. gl_FragColor = vec4(yiq, 1.0);
  72. }
  73. ]]></fragment>
  74.  
  75. <!-- 2nd pass - Create composite signal,
  76. low-pass and demodulate separately -->
  77. <vertex><![CDATA[
  78. #version 120
  79. uniform mat4 rubyMVPMatrix;
  80. attribute vec2 rubyVertexCoord;
  81. attribute vec2 rubyTexCoord;
  82. uniform vec2 rubyTextureSize;
  83. uniform vec2 rubyOutputSize;
  84.  
  85. varying vec2 tex_coord;
  86.  
  87. varying vec2 pix_no;
  88.  
  89. void main()
  90. {
  91. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  92. tex_coord = rubyTexCoord;
  93. pix_no = rubyTexCoord * rubyTextureSize;
  94. }
  95. ]]></vertex>
  96. <fragment filter="nearest" scale="1.0" frame_count_mod="2" float_framebuffer="true"><![CDATA[
  97. #version 120
  98. uniform sampler2D rubyTexture;
  99. uniform vec2 rubyTextureSize;
  100. uniform int rubyFrameCount;
  101. varying vec2 tex_coord;
  102.  
  103. varying vec2 pix_no;
  104.  
  105. #define PI 3.14159265
  106. #define CHROMA_MOD_FREQ (0.4 * PI)
  107.  
  108. #define CHROMA_AMP 1.0
  109. #define SATURATION 1.0
  110. #define BRIGHTNESS 1.0
  111. #define chroma_mod (2.0 * SATURATION / CHROMA_AMP)
  112.  
  113. const float filter[9] = float[9](
  114. 0.0019, 0.0031, -0.0108, 0.0, 0.0407,
  115. -0.0445, -0.0807, 0.2913, 0.5982
  116. );
  117.  
  118. vec3 fetch_offset(float offset, float one_x)
  119. {
  120. return texture2D(rubyTexture, tex_coord + vec2(offset * one_x, 0.0)).xyz;
  121. }
  122.  
  123. void main()
  124. {
  125. float one_x = 1.0 / rubyTextureSize.x;
  126. float chroma_phase = PI * 0.6667 * (mod(pix_no.y, 3.0) + float(rubyFrameCount));
  127. float mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ;
  128.  
  129. float signal = 0.0;
  130. for (int i = 0; i < 8; i++)
  131. {
  132. float offset = float(i);
  133. float sums =
  134. dot(fetch_offset(offset - 8.0, one_x), vec3(1.0)) +
  135. dot(fetch_offset(8.0 - offset, one_x), vec3(1.0));
  136.  
  137. signal += sums * filter[i];
  138. }
  139. signal += dot(texture2D(rubyTexture, tex_coord).xyz, vec3(1.0)) * filter[8];
  140.  
  141. float i_mod = chroma_mod * cos(mod_phase);
  142. float q_mod = chroma_mod * sin(mod_phase);
  143.  
  144. vec3 out_color = vec3(signal) * vec3(BRIGHTNESS, i_mod, q_mod);
  145. gl_FragColor = vec4(out_color, 1.0);
  146. }
  147. ]]></fragment>
  148.  
  149. <!-- 3rd pass - Low-pass luma and chroma, decode to RGB -->
  150. <vertex><![CDATA[
  151. #version 120
  152. uniform mat4 rubyMVPMatrix;
  153. attribute vec2 rubyVertexCoord;
  154. attribute vec2 rubyTexCoord;
  155. varying vec2 tex_coord;
  156.  
  157. void main()
  158. {
  159. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  160. tex_coord = rubyTexCoord;
  161. }
  162. ]]></vertex>
  163. <fragment scale="1.0" filter="nearest"><![CDATA[
  164. #version 120
  165. varying vec2 tex_coord;
  166. uniform sampler2D rubyTexture;
  167. uniform vec2 rubyTextureSize;
  168.  
  169. #define NTSC_GAMMA 2.2
  170.  
  171. const float luma_filter[9] = float[9](
  172. -0.0020, -0.0009, 0.0038, 0.0178, 0.0445,
  173. 0.0817, 0.1214, 0.1519, 0.1634
  174. );
  175.  
  176. const float chroma_filter[9] = float[9](
  177. 0.0046, 0.0082, 0.0182, 0.0353, 0.0501,
  178. 0.0832, 0.1062, 0.1222, 0.1280
  179. );
  180.  
  181. const mat3 yiq2rgb_mat = mat3(
  182. 1.0, 1.0, 1.0,
  183. 0.956, -0.2720, -1.1060,
  184. 0.6210, -0.6474, 1.7046);
  185.  
  186. vec3 yiq2rgb(vec3 yiq)
  187. {
  188. return yiq2rgb_mat * yiq;
  189. }
  190.  
  191. vec3 fetch_offset(float offset, float one_x)
  192. {
  193. return texture2D(rubyTexture, tex_coord + vec2(offset * one_x, 0.0)).xyz;
  194. }
  195.  
  196. void main()
  197. {
  198. float one_x = 1.0 / rubyTextureSize.x;
  199. vec3 signal = vec3(0.0);
  200. for (int i = 0; i < 8; i++)
  201. {
  202. float offset = float(i);
  203.  
  204. vec3 sums = fetch_offset(offset - 8.0, one_x) +
  205. fetch_offset(8.0 - offset, one_x);
  206.  
  207. signal += sums * vec3(luma_filter[i], chroma_filter[i], chroma_filter[i]);
  208. }
  209. signal += texture2D(rubyTexture, tex_coord).xyz *
  210. vec3(luma_filter[8], chroma_filter[8], chroma_filter[8]);
  211.  
  212. vec3 rgb = pow(yiq2rgb(signal), vec3(NTSC_GAMMA));
  213. gl_FragColor = vec4(rgb, 1.0);
  214. }
  215. ]]></fragment>
  216. <vertex><![CDATA[
  217. uniform mat4 rubyMVPMatrix;
  218. uniform vec2 rubyTextureSize;
  219. uniform vec2 rubyInputSize;
  220. uniform vec2 rubyOutputSize;
  221. attribute vec2 rubyVertexCoord;
  222. attribute vec2 rubyTexCoord;
  223. attribute vec2 rubyLUTTexCoord;
  224. varying vec2 tex_coord;
  225. varying vec2 lut_coord;
  226. varying vec2 omega;
  227.  
  228. void main()
  229. {
  230. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  231. tex_coord = rubyTexCoord;
  232. lut_coord = rubyLUTTexCoord;
  233. omega = vec2(3.1415 * rubyOutputSize.x * rubyTextureSize.x / rubyInputSize.x, 2.0 * 3.1415 * rubyTextureSize.y);
  234. }
  235. ]]></vertex>
  236. <fragment filter="linear" outscale="2.0"><![CDATA[
  237. uniform sampler2D rubyTexture;
  238. uniform sampler2D phosphorLUT;
  239. uniform vec2 rubyTextureSize;
  240. uniform vec2 rubyInputSize;
  241. uniform vec2 rubyOutputSize;
  242. varying vec2 tex_coord;
  243. varying vec2 lut_coord;
  244. varying vec2 omega;
  245.  
  246. const float base_brightness = 0.95;
  247. const vec2 sine_comp = vec2(0.05, 0.85);
  248.  
  249. void main()
  250. {
  251. vec4 frame = texture2D(rubyTexture, tex_coord.xy);
  252. vec4 inverse = 1 - texture2D(rubyTexture, tex_coord.xy);
  253. vec4 screen = texture2D(phosphorLUT, lut_coord.xy);
  254. vec4 final = screen - inverse;
  255. vec4 scanline = final * (base_brightness + dot(sine_comp * sin(tex_coord.xy * omega), vec2(1.0)));
  256.  
  257. gl_FragColor = clamp(scanline, 0.0, 1.0);
  258. }
  259. ]]></fragment>
  260. <vertex><![CDATA[
  261. #version 120
  262. uniform mat4 rubyMVPMatrix;
  263. attribute vec2 rubyVertexCoord;
  264. attribute vec2 rubyTexCoord;
  265. varying vec2 tex_coord;
  266.  
  267. varying vec2 pix_no;
  268. uniform vec2 rubyTextureSize;
  269. uniform vec2 rubyInputSize;
  270. uniform vec2 rubyOutputSize;
  271.  
  272. void main()
  273. {
  274. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  275. tex_coord = rubyTexCoord;
  276. pix_no = rubyTexCoord * rubyTextureSize * (rubyOutputSize / rubyInputSize);
  277. }
  278. ]]></vertex>
  279. <fragment filter="linear" outscale="1.0"><![CDATA[
  280. uniform sampler2D rubyTexture;
  281. uniform vec2 rubyTextureSize;
  282. uniform vec2 rubyInputSize;
  283. uniform vec2 rubyOutputSize;
  284. varying vec2 tex_coord;
  285.  
  286. #define CRTgamma 2.5
  287. #define display_gamma 2.0
  288. #define TEX2D(c) pow(texture2D(rubyTexture,(c)),vec4(CRTgamma))
  289.  
  290. void main()
  291. {
  292. vec2 xy = tex_coord.st;
  293. float oney = 1.0/rubyTextureSize.y;
  294.  
  295. float wid = 2.0;
  296.  
  297. float c1 = exp(-1.0/wid/wid);
  298. float c2 = exp(-4.0/wid/wid);
  299. float c3 = exp(-9.0/wid/wid);
  300. float c4 = exp(-16.0/wid/wid);
  301. float norm = 1.0 / (1.0 + 2.0*(c1+c2+c3+c4));
  302.  
  303. vec4 sum = vec4(0.0);
  304.  
  305. sum += TEX2D(xy + vec2(0.0, -4.0 * oney)) * vec4(c4);
  306. sum += TEX2D(xy + vec2(0.0, -3.0 * oney)) * vec4(c3);
  307. sum += TEX2D(xy + vec2(0.0, -2.0 * oney)) * vec4(c2);
  308. sum += TEX2D(xy + vec2(0.0, -1.0 * oney)) * vec4(c1);
  309. sum += TEX2D(xy);
  310. sum += TEX2D(xy + vec2(0.0, +1.0 * oney)) * vec4(c1);
  311. sum += TEX2D(xy + vec2(0.0, +2.0 * oney)) * vec4(c2);
  312. sum += TEX2D(xy + vec2(0.0, +3.0 * oney)) * vec4(c3);
  313. sum += TEX2D(xy + vec2(0.0, +4.0 * oney)) * vec4(c4);
  314.  
  315. gl_FragColor = pow(sum*vec4(norm),vec4(1.0/display_gamma));
  316. }
  317. ]]></fragment>
  318. <vertex><![CDATA[
  319. #version 120
  320. uniform mat4 rubyMVPMatrix;
  321. attribute vec2 rubyVertexCoord;
  322. attribute vec2 rubyTexCoord;
  323. varying vec2 tex_coord;
  324.  
  325. varying vec2 pix_no;
  326. uniform vec2 rubyTextureSize;
  327. uniform vec2 rubyInputSize;
  328. uniform vec2 rubyOutputSize;
  329.  
  330. void main()
  331. {
  332. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  333. tex_coord = rubyTexCoord;
  334. pix_no = rubyTexCoord * rubyTextureSize * (rubyOutputSize / rubyInputSize);
  335. }
  336. ]]></vertex>
  337. <fragment filter="linear" outscale="1.0"><![CDATA[
  338. uniform sampler2D rubyTexture;
  339. uniform vec2 rubyTextureSize;
  340. uniform vec2 rubyInputSize;
  341. uniform vec2 rubyOutputSize;
  342. varying vec2 tex_coord;
  343.  
  344. #define CRTgamma 2.5
  345. #define display_gamma 2.0
  346. #define TEX2D(c) pow(texture2D(rubyTexture,(c)),vec4(CRTgamma))
  347.  
  348. void main()
  349. {
  350. vec2 xy = tex_coord.st;
  351. float oney = 1.0/rubyTextureSize.x;
  352.  
  353. float wid = 2.0;
  354.  
  355. float c1 = exp(-1.0/wid/wid);
  356. float c2 = exp(-4.0/wid/wid);
  357. float c3 = exp(-9.0/wid/wid);
  358. float c4 = exp(-16.0/wid/wid);
  359. float norm = 1.0 / (1.0 + 2.0*(c1+c2+c3+c4));
  360.  
  361. vec4 sum = vec4(0.0);
  362.  
  363. sum += TEX2D(xy + vec2(0.0, -4.0 * oney)) * vec4(c4);
  364. sum += TEX2D(xy + vec2(0.0, -3.0 * oney)) * vec4(c3);
  365. sum += TEX2D(xy + vec2(0.0, -2.0 * oney)) * vec4(c2);
  366. sum += TEX2D(xy + vec2(0.0, -1.0 * oney)) * vec4(c1);
  367. sum += TEX2D(xy);
  368. sum += TEX2D(xy + vec2(0.0, +1.0 * oney)) * vec4(c1);
  369. sum += TEX2D(xy + vec2(0.0, +2.0 * oney)) * vec4(c2);
  370. sum += TEX2D(xy + vec2(0.0, +3.0 * oney)) * vec4(c3);
  371. sum += TEX2D(xy + vec2(0.0, +4.0 * oney)) * vec4(c4);
  372.  
  373. gl_FragColor = pow(sum*vec4(norm),vec4(1.0/display_gamma));
  374. }
  375. ]]></fragment>
  376. <vertex><![CDATA[
  377. attribute vec2 rubyOrigTexCoord;
  378. varying vec2 orig_tex;
  379. uniform mat4 rubyMVPMatrix;
  380. attribute vec2 rubyVertexCoord;
  381. attribute vec2 rubyTexCoord;
  382. varying vec2 lut_coord;
  383. attribute vec2 rubyLUTTexCoord;
  384. varying vec2 tex_coord;
  385.  
  386. void main()
  387. {
  388. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  389. orig_tex = rubyOrigTexCoord;
  390. lut_coord.xy = rubyLUTTexCoord.xy;
  391. }
  392. ]]></vertex>
  393. <fragment filter="linear" outscale="1.0"><![CDATA[
  394. uniform sampler2D rubyOrigTexture;
  395. uniform sampler2D phosphorLUT;
  396. varying vec2 orig_tex;
  397. uniform float brightness;
  398. varying vec2 lut_coord;
  399.  
  400. void main()
  401. {
  402. float brightness = 1.1;
  403. vec4 frame = texture2D(rubyOrigTexture, orig_tex);
  404. vec4 inverse = 1 - (brightness * texture2D(rubyOrigTexture, orig_tex));
  405. vec4 screen = texture2D(phosphorLUT, lut_coord);
  406.  
  407. gl_FragColor = screen - inverse;
  408. }
  409. ]]></fragment>
  410. <vertex><![CDATA[
  411. uniform mat4 rubyMVPMatrix;
  412. attribute vec2 rubyVertexCoord;
  413. attribute vec2 rubyPass4TexCoord;
  414. attribute vec2 rubyPass5TexCoord;
  415. varying vec2 pass4_tex;
  416. varying vec2 pass5_tex;
  417. attribute vec2 rubyTexCoord;
  418. varying vec2 tex_coord;
  419.  
  420. void main() {
  421. gl_Position = rubyMVPMatrix * vec4(rubyVertexCoord, 0.0, 1.0);
  422. tex_coord = rubyTexCoord;
  423. pass4_tex = rubyPass4TexCoord;
  424. pass5_tex = rubyPass5TexCoord;
  425. }
  426. ]]></vertex>
  427. <fragment filter="linear"><![CDATA[
  428. uniform sampler2D rubyPass4Texture; // Result from Pass 4.
  429. uniform sampler2D rubyPass5Texture; // Result from Pass 5.
  430. uniform sampler2D rubyTexture; // Result from Pass 3 (previous pass).
  431. varying vec2 pass4_tex;
  432. varying vec2 pass5_tex;
  433. varying vec2 tex_coord;
  434.  
  435. void main() {
  436. vec4 pass4 = texture2D(rubyPass4Texture, pass4_tex);
  437. vec4 pass5 = texture2D(rubyPass5Texture, pass5_tex);
  438. vec4 pass6 = texture2D(rubyTexture, tex_coord.xy);
  439.  
  440. gl_FragColor = 1.0 - (1.0 - pass4) * (1.0 - pass5);
  441. }
  442. ]]></fragment>
  443. </shader>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement