ProjectArcade

Форк
0
410 строк · 11.9 Кб
1
#include "ReShade.fxh"
2

3
/* COMPATIBILITY
4
   - HLSL compilers
5
   - Cg   compilers
6
*/
7

8
/*
9
    CRT-interlaced
10

11
    Copyright (C) 2010-2012 cgwg, Themaister and DOLLS
12

13
    This program is free software; you can redistribute it and/or modify it
14
    under the terms of the GNU General Public License as published by the Free
15
    Software Foundation; either version 2 of the License, or (at your option)
16
    any later version.
17

18
    (cgwg gave their consent to have the original version of this shader
19
    distributed under the GPL in this message:
20

21
        http://board.byuu.org/viewtopic.php?p=26075#p26075
22

23
        "Feel free to distribute my shaders under the GPL. After all, the
24
        barrel distortion code was taken from the Curvature shader, which is
25
        under the GPL."
26
    )
27
	This shader variant is pre-configured with screen curvature
28
*/
29

30
uniform float texture_sizeX <
31
	ui_type = "drag";
32
	ui_min = 1.0;
33
	ui_max = BUFFER_WIDTH;
34
	ui_label = "Screen Width [CRT-Geom]";
35
> = 240.0;
36

37
uniform float texture_sizeY <
38
	ui_type = "drag";
39
	ui_min = 1.0;
40
	ui_max = BUFFER_HEIGHT;
41
	ui_label = "Screen Height [CRT-Geom]";
42
> = 240.0;
43

44
uniform float video_sizeX <
45
	ui_type = "drag";
46
	ui_min = 1.0;
47
	ui_max = BUFFER_WIDTH;
48
	ui_label = "Frame Width [CRT-Geom]";
49
	ui_tooltip = "This should be sized according to the video data in the texture (If you're using emulators, set this to the Emu video frame size, otherwise, keep it the same as Screen Width/Height or Fullscreen res.)";
50
> = 240.0;
51

52
uniform float video_sizeY <
53
	ui_type = "drag";
54
	ui_min = 1.0;
55
	ui_max = BUFFER_HEIGHT;
56
	ui_label = "Frame Height [CRT-Geom]";
57
	ui_tooltip = "This should be sized according to the video data in the texture (If you're using emulators, set this to the Emu video frame size, otherwise, keep it the same as Screen Width/Height or Fullscreen res.)";
58
> = 240.0;
59

60
uniform float CRTgamma <
61
	ui_type = "drag";
62
	ui_min  = 0.1;
63
	ui_max = 5.0;
64
	ui_step = 0.1;
65
	ui_label = "Target Gamma [CRT-Geom]";
66
> = 2.4;
67

68
uniform float monitorgamma <
69
	ui_type = "drag";
70
	ui_min = 0.1;
71
	ui_max = 5.0;
72
	ui_step = 0.1;
73
	ui_label = "Monitor Gamma [CRT-Geom]";
74
> = 2.2;
75

76
uniform float d <
77
	ui_type = "drag";
78
	ui_min = 0.1;
79
	ui_max = 3.0;
80
	ui_step = 0.1;
81
	ui_label =  "Distance [CRT-Geom]";
82
> = 1.5;
83

84
uniform float CURVATURE <
85
	ui_type = "drag";
86
	ui_min = 0.0;
87
	ui_max = 1.0;
88
	ui_step = 1.0;
89
	ui_label = "Curvature Toggle [CRT-Geom]";
90
> = 1.0;
91

92
uniform float R <
93
	ui_type = "drag";
94
	ui_min = 0.0;
95
	ui_max = 10.0;
96
	ui_step = 0.1;
97
	ui_label = "Curvature Radius [CRT-Geom]";
98
> = 2.0;
99

100
uniform float cornersize <
101
	ui_type = "drag";
102
	ui_min = 0.001;
103
	ui_max = 1.0;
104
	ui_step = 0.005;
105
	ui_label = "Corner Size [CRT-Geom]";
106
> = 0.03;
107

108
uniform float cornersmooth <
109
	ui_type = "drag";
110
	ui_min = 80.0;
111
	ui_max = 2000.0;
112
	ui_step = 100.0;
113
	ui_label = "Corner Smoothness [CRT-Geom]";
114
> = 1000.0;
115

116
uniform float x_tilt <
117
	ui_type = "drag";
118
	ui_min = -0.5;
119
	ui_max = 0.5;
120
	ui_step = 0.05;
121
	ui_label = "Horizontal Tilt [CRT-Geom]";
122
> = 0.0;
123

124
uniform float y_tilt <
125
	ui_type = "drag";
126
	ui_min = -0.5;
127
	ui_max = 0.5;
128
	ui_step = 0.05;
129
	ui_label = "Vertical Tilt [CRT-Geom]";
130
> = 0.0;
131

132
uniform float overscan_x <
133
	ui_type = "drag";
134
	ui_min = -125.0;
135
	ui_max = 125.0;
136
	ui_step = 1.0;
137
	ui_label = "Horiz. Overscan % [CRT-Geom]";
138
> = 100.0;
139

140
uniform float overscan_y <
141
	ui_type = "drag";
142
	ui_min = -125.0;
143
	ui_max = 125.0;
144
	ui_step = 1.0;
145
	ui_label = "Vert. Overscan % [CRT-Geom]";
146
> = 100.0;
147

148
uniform float DOTMASK <
149
	ui_type = "drag";
150
	ui_min = 0.0;
151
	ui_max = 0.3;
152
	ui_step = 0.3;
153
	ui_label = "Dot Mask Toggle [CRT-Geom]";
154
> = 0.3;
155

156
uniform float SHARPER <
157
	ui_type = "drag";
158
	ui_min = 1.0;
159
	ui_max = 3.0;
160
	ui_step = 1.0;
161
	ui_label = "Sharpness [CRT-Geom]";
162
> = 3.0;
163

164
uniform float scanline_weight <
165
	ui_type = "drag";
166
	ui_min = 0.1;
167
	ui_max = 0.5;
168
	ui_step = 0.01;
169
	ui_label = "Scanline Weight [CRT-Geom]";
170
> = 0.3;
171

172
uniform float lum <
173
	ui_type = "drag";
174
	ui_min = 0.0;
175
	ui_max = 1.0;
176
	ui_step = 0.01;
177
	ui_label = "Luminance Boost [CRT-Geom]";
178
> = 0.0;
179

180
uniform float interlace_toggle <
181
	ui_type = "drag";
182
	ui_min = 1.0;
183
	ui_max = 5.0;
184
	ui_step = 4.0;
185
	ui_label = "Interlacing [CRT-Geom]";
186
> = 1.0;
187

188
uniform bool OVERSAMPLE <
189
	ui_tooltip = "Enable 3x oversampling of the beam profile; improves moire effect caused by scanlines+curvature";
190
> = true;
191

192
uniform bool INTERLACED <
193
	ui_tooltip = "Use interlacing detection; may interfere with other shaders if combined";
194
> = true;
195

196
#define FIX(c) max(abs(c), 1e-5);
197
#define PI 3.141592653589
198

199
#define TEX2D(c) pow(tex2D(ReShade::BackBuffer, (c)), float4(CRTgamma,CRTgamma,CRTgamma,CRTgamma))
200
#define texture_size float2(texture_sizeX, texture_sizeY)
201
#define video_size float2(video_sizeX, video_sizeY)
202

203
static const float2 aspect = float2(1.0, 0.75);
204

205
uniform int framecount < source = "framecount"; >;
206

207
float fmod(float a, float b)
208
{
209
  float c = frac(abs(a/b))*abs(b);
210
  return (a < 0) ? -c : c;   /* if ( a < 0 ) c = 0-c */
211
}
212

213
float intersect(float2 xy, float2 sinangle, float2 cosangle)
214
{
215
    float A = dot(xy,xy)+d*d;
216
    float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
217
	float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
218
    return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
219
}
220

221
float2 bkwtrans(float2 xy, float2 sinangle, float2 cosangle)
222
{
223
    float c = intersect(xy, sinangle, cosangle);
224
	float2 pnt = float2(c,c)*xy;
225
	pnt -= float2(-R,-R)*sinangle;
226
	pnt /= float2(R,R);
227
	float2 tang = sinangle/cosangle;
228
	float2 poc = pnt/cosangle;
229
	float A = dot(tang,tang)+1.0;
230
	float B = -2.0*dot(poc,tang);
231
	float C = dot(poc,poc)-1.0;
232
	float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
233
	float2 uv = (pnt-a*sinangle)/cosangle;
234
	float r = FIX(R*acos(a));
235
	return uv*r/sin(r/R);
236
}
237

238
float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle)
239
{
240
	float r = FIX(sqrt(dot(uv,uv)));
241
	uv *= sin(r/R)/r;
242
	float x = 1.0-cos(r/R);
243
	float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle);
244
	return d*(uv*cosangle-x*sinangle)/D;
245
}
246

247
float3 maxscale(float2 sinangle, float2 cosangle)
248
{
249
	float2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y), sinangle, cosangle);
250
	float2 a = float2(0.5,0.5)*aspect;
251
	float2 lo = float2(fwtrans(float2(-a.x,c.y), sinangle, cosangle).x,
252
						fwtrans(float2(c.x,-a.y), sinangle, cosangle).y)/aspect;
253
	float2 hi = float2(fwtrans(float2(+a.x,c.y), sinangle, cosangle).x,
254
						fwtrans(float2(c.x,+a.y), sinangle, cosangle).y)/aspect;
255
	return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));
256
}
257

258
float4 scanlineWeights(float distance, float4 color)
259
{
260
		// "wid" controls the width of the scanline beam, for each RGB
261
		// channel The "weights" lines basically specify the formula
262
		// that gives you the profile of the beam, i.e. the intensity as
263
		// a function of distance from the vertical center of the
264
		// scanline. In this case, it is gaussian if width=2, and
265
		// becomes nongaussian for larger widths. Ideally this should
266
		// be normalized so that the integral across the beam is
267
		// independent of its width. That is, for a narrower beam
268
		// "weights" should have a higher peak at the center of the
269
		// scanline than for a wider beam.
270
        float4 wid = 2.0 + 2.0 * pow(color, float4(4.0,4.0,4.0,4.0));
271
        float weights = float(distance / scanline_weight);
272
        return (lum + 1.4) * exp(-pow(weights * rsqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
273
}
274

275
float4 PS_CRTGeom(float4 vpos : SV_Position, float2 uv : TexCoord) : SV_Target
276
{
277

278
	float2 TextureSize = float2(SHARPER * texture_size.x, texture_size.y);
279
	float mod_factor = uv.x * texture_size.x * ReShade::ScreenSize.x / video_size.x;
280
	float2 ilfac = float2(1.0,clamp(floor(video_size.y/(200.0 * interlace_toggle)),1.0,2.0));
281
	float2 sinangle = sin(float2(x_tilt, y_tilt));
282
	float2 cosangle = cos(float2(x_tilt, y_tilt));
283
	float3 stretch = maxscale(sinangle, cosangle);
284
	float2 one = ilfac / TextureSize;
285

286
	// Here's a helpful diagram to keep in mind while trying to
287
	// understand the code:
288
	//
289
	//  |      |      |      |      |
290
	// -------------------------------
291
	//  |      |      |      |      |
292
	//  |  01  |  11  |  21  |  31  | <-- current scanline
293
	//  |      | @    |      |      |
294
	// -------------------------------
295
	//  |      |      |      |      |
296
	//  |  02  |  12  |  22  |  32  | <-- next scanline
297
	//  |      |      |      |      |
298
	// -------------------------------
299
	//  |      |      |      |      |
300
	//
301
	// Each character-cell represents a pixel on the output
302
	// surface, "@" represents the current pixel (always somewhere
303
	// in the bottom half of the current scan-line, or the top-half
304
	// of the next scanline). The grid of lines represents the
305
	// edges of the texels of the underlying texture.
306

307
	// Texture coordinates of the texel containing the active pixel.
308
	float2 xy = 0.0;
309
	if (CURVATURE > 0.5){
310
		float2 cd = uv;
311
		cd *= texture_size / video_size;
312
		cd = (cd-float2(0.5,0.5))*aspect*stretch.z+stretch.xy;
313
		xy =  (bkwtrans(cd, sinangle, cosangle)/float2(overscan_x / 100.0, overscan_y / 100.0)/aspect+float2(0.5,0.5)) * video_size / texture_size;
314
	} else {
315
		xy = uv;
316
	}
317

318
	float2 cd2 = xy;
319
	cd2 *= texture_size / video_size;
320
	cd2 = (cd2 - float2(0.5,0.5)) * float2(overscan_x / 100.0, overscan_y / 100.0) + float2(0.5,0.5);
321
	cd2 = min(cd2, float2(1.0,1.0)-cd2) * aspect;
322
	float2 cdist = float2(cornersize,cornersize);
323
	cd2 = (cdist - min(cd2,cdist));
324
	float dist = sqrt(dot(cd2,cd2));
325
	float cval = clamp((cdist.x-dist)*cornersmooth,0.0, 1.0);
326

327
	float2 xy2 = ((xy*TextureSize/video_size-float2(0.5,0.5))*float2(1.0,1.0)+float2(0.5,0.5))*video_size/TextureSize;
328
	// Of all the pixels that are mapped onto the texel we are
329
	// currently rendering, which pixel are we currently rendering?
330
	float2 ilfloat = float2(0.0,ilfac.y > 1.5 ? fmod(float(framecount),2.0) : 0.0);
331

332
	float2 ratio_scale = (xy * TextureSize - float2(0.5,0.5) + ilfloat)/ilfac;
333
      
334
	float filter = video_size.y / ReShade::ScreenSize.y;
335
	float2 uv_ratio = frac(ratio_scale);
336

337
	// Snap to the center of the underlying texel.
338

339
	xy = (floor(ratio_scale)*ilfac + float2(0.5,0.5) - ilfloat) / TextureSize;
340

341
	// Calculate Lanczos scaling coefficients describing the effect
342
	// of various neighbour texels in a scanline on the current
343
	// pixel.
344
	float4 coeffs = PI * float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
345

346
	// Prevent division by zero.
347
	coeffs = FIX(coeffs);
348

349
	// Lanczos2 kernel.
350
	coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
351

352
	// Normalize.
353
	coeffs /= dot(coeffs, float4(1.0,1.0,1.0,1.0));
354

355
	// Calculate the effective colour of the current and next
356
	// scanlines at the horizontal location of the current pixel,
357
	// using the Lanczos coefficients above.
358
    float4 col  = clamp(mul(coeffs, float4x4(
359
		TEX2D(xy + float2(-one.x, 0.0)),
360
		TEX2D(xy),
361
		TEX2D(xy + float2(one.x, 0.0)),
362
		TEX2D(xy + float2(2.0 * one.x, 0.0)))),
363
	0.0, 1.0);
364
		
365
    float4 col2 = clamp(mul(coeffs, float4x4(
366
		TEX2D(xy + float2(-one.x, one.y)),
367
		TEX2D(xy + float2(0.0, one.y)),
368
		TEX2D(xy + one),
369
		TEX2D(xy + float2(2.0 * one.x, one.y)))),
370
	0.0, 1.0);
371

372
	// Calculate the influence of the current and next scanlines on
373
	// the current pixel.
374
	float4 weights  = scanlineWeights(uv_ratio.y, col);
375
	float4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
376
	
377
	if (OVERSAMPLE){
378
		uv_ratio.y =uv_ratio.y+1.0/3.0*filter;
379
		weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;
380
		weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;
381
		uv_ratio.y =uv_ratio.y-2.0/3.0*filter;
382
		weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;
383
		weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;
384
	}
385
	float3 mul_res  = (col * weights + col2 * weights2).rgb;
386
	mul_res *= float3(cval,cval,cval);
387

388
	// dot-mask emulation:
389
	// Output pixels are alternately tinted green and magenta.
390
	float3 dotMaskWeights = lerp(
391
		float3(1.0, 1.0 - DOTMASK, 1.0),
392
		float3(1.0 - DOTMASK, 1.0, 1.0 - DOTMASK),
393
		floor(fmod(mod_factor, 2.0))
394
	); 
395
	mul_res *= dotMaskWeights;
396
        
397
		
398
	// Convert the image gamma for display on our output device.
399
	mul_res = pow(mul_res, float3(1.0 / monitorgamma,1.0 / monitorgamma,1.0 / monitorgamma));
400

401
	// Color the texel.
402
	return float4(mul_res, 1.0);
403
}
404

405
technique GeomCRT {
406
	pass CRT_Geom {
407
		VertexShader=PostProcessVS;
408
		PixelShader=PS_CRTGeom;
409
	}
410
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.