Pete´s Messageboard... No ISO/BIOS requests!

Homepage Members Register Login Search Old board


Neuer Thread ...
More : [1] [2]


AuthorTopics » Book an abo for this threadClose Thread Move Thread Fix the thread Print view Delete this thread

GPDP 



...

Status:Offline
Date registered: 27.12.2012
Post:5
Send Message
...   Created on 27.12.2012 - 07:40Jump to top Quote this post Report this post Edit Delete


gblues schrieb

    I've successfully ported a CRT shader from BSNES!

    Requirements:

    1) Internal X Resolution and Internal Y Resolution settings must both be set to "0: Low - native PSX resolution"
    2) Disable "Screen Filtering" and "Scanlines" settings.


Interestingly, I had just made a few tweaks to the older code in this thread the other night, and posted it in the ngemu forums. The only difference is that your solution to converting the rubyInputSize and rubyOutputSize parameters is more elegant than mine, as it takes the information from OGL2Size rather than specifying a resolution for both.

However, I should say that as it stands, your code gives the whole screen a slight magenta tint. After testing some things out, I figured out the problem lies in this line:

vec2 rubyOutputSize = vec2(OGL2Size.z, OGL2Size.w);

Changing the z and w into x and y respectively fixes this. However, when setting the internal resolution to 0, it does result in magenta and cyan lines covering the screen.

That, too, is easily solved, however. Just crank up the internal X resolution to 2 (leave the Y at 0, though), and the lines disappear, resulting in no discoloration, and it makes the graphics sharper to boot!

However, the downside to this is that some games work well with the shader, while others do not. From what I've tested, FFVII, FFIX, Silent Hill, Breath of Fire 4, Megaman X4, and Vagrant Story all work well with absolutely no discoloration with internal X resolution set to 2, but Spyro, Crash 2, Final Fantasy Tactics, and DQ7 have some kind of discoloration no matter what you do. I'm unsure if this is due to some weird resolution these games use or something, but there are definitely visible color stripes on these games which I cannot get rid of no matter what I tweak in the plugin settings or on the shader itself. Castlevania: SOTN I believe also has a little discoloration, but it's almost unnoticeable unless you look reaaaaaaally close at your screen.

Overall, it's kind of a mixed bag, but most of the games you'd want to play with scanlines work perfectly (mostly 2D games or games with pre-rendered backgrounds like most RPGs), and the few that do not... well, unless something comes up, there's always RetroArch with the Mednafen core, I suppose.

Edit: I should mention this is all tested at a resolution of 1276x960, which is a direct 4x scale of the native resolution of most PS1 games, since the shader is stated to work best at a scale of 4x or greater. If you're wondering why 1276 rather than 1280, I found that for some reason at 1280, four vertical lines appear on the screen, which are most noticeable in bright areas. Cutting out 4 pixels from the horizontal resolution makes those lines disappear. Perhaps the solution to the games that have a lot of discoloration has something to do with the horizontal resolution, but I cannot be arsed to be testing out a myriad resolutions to find out.

Edit 2: Well, using the new method to convert rubyInputSize and rubyOutputSize from gblues, I managed to successfully port the very latest non-interlaced version of cgwg's CRT shader. The difference is rather miniscule, but if you have a sharp eye, it's definitely better, although the same problems outlined above still exist. Here's the code:

gpuPeteOGL2.slv:

Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
 
        varying float CRTgamma;
        varying float monitorgamma;
        varying vec2 overscan;
        varying vec2 aspect;
        varying float d;
        varying float R;
        varying float cornersize;
        varying float cornersmooth;

        varying vec3 stretch;
        varying vec2 sinangle;
        varying vec2 cosangle;

        uniform vec4 OGL2Param, OGL2Size;

        vec2 rubyTextureSize = vec2(OGL2Size.x, OGL2Size.y);
        vec2 rubyInputSize = vec2(OGL2Size.x, OGL2Size.y);
        vec2 rubyOutputSize = vec2(OGL2Size.x, OGL2Size.y);

        varying vec2 texCoord;
        varying vec2 one;
        varying float mod_factor;

        #define FIX(c) max(abs(c), 1e-5);

        float intersect(vec2 xy)
        {
                float A = dot(xy,xy)+d*d;
                float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
                float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
                return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
        }

        vec2 bkwtrans(vec2 xy)
        {
                float c = intersect(xy);
                vec2 point = vec2(c)*xy;
                point -= vec2(-R)*sinangle;
                point /= vec2(R);
                vec2 tang = sinangle/cosangle;
                vec2 poc = point/cosangle;
                float A = dot(tang,tang)+1.0;
                float B = -2.0*dot(poc,tang);
                float C = dot(poc,poc)-1.0;
                float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
                vec2 uv = (point-a*sinangle)/cosangle;
                float r = R*acos(a);
                return uv*r/sin(r/R);
        }

        vec2 fwtrans(vec2 uv)
        {
                float r = FIX(sqrt(dot(uv,uv)));
                uv *= sin(r/R)/r;
                float x = 1.0-cos(r/R);
                float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle);
                return d*(uv*cosangle-x*sinangle)/D;
        }

        vec3 maxscale()
        {
                vec2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y));
                vec2 a = vec2(0.5,0.5)*aspect;
                vec2 lo = vec2(fwtrans(vec2(-a.x,c.y)).x,
                             fwtrans(vec2(c.x,-a.y)).y)/aspect;
                vec2 hi = vec2(fwtrans(vec2(+a.x,c.y)).x,
                             fwtrans(vec2(c.x,+a.y)).y)/aspect;
                return vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));
        }


        void main()
        {
                // START of parameters

                // gamma of simulated CRT
                CRTgamma = 2.4;
                // gamma of display monitor (typically 2.2 is correct)
                monitorgamma = 2.2;
                // overscan (e.g. 1.02 for 2% overscan)
                overscan = vec2(0.00,0.00);
                // aspect ratio
                aspect = vec2(1.0, 0.75);
                // lengths are measured in units of (approximately) the width
                // of the monitor simulated distance from viewer to monitor
                d = 2.0;
                // radius of curvature
                R = 1.5;
                // tilt angle in radians
                // (behavior might be a bit wrong if both components are
                // nonzero)
                const vec2 angle = vec2(0.0,-0.15);
                // size of curved corners
                cornersize = 0.001;
                // border smoothness parameter
                // decrease if borders are too aliased
                cornersmooth = 1000.0;

                // END of parameters

                // Do the standard vertex processing.
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

                // Precalculate a bunch of useful values we'll need in the fragment
                // shader.
                sinangle = sin(angle);
                cosangle = cos(angle);
                stretch = maxscale();

                // Texture coords.
                texCoord = gl_MultiTexCoord0.xy;

                // The size of one texel, in texture-coordinates.
                one = 1.0 / rubyTextureSize;

                // Resulting X pixel-coordinate of the pixel we're drawing.
                mod_factor = texCoord.x * rubyTextureSize.x * rubyOutputSize.x / rubyInputSize.x;
        }


gpuPeteOGL2.slf:
Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
 
/*
    CRT shader

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

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

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

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

        "Feel free to distribute my shaders under the GPL. After all, the
        barrel distortion code was taken from the Curvature shader, which is
        under the GPL."
    )
*/

        // Comment the next line to disable interpolation in linear gamma (and
        // gain speed).
        #define LINEAR_PROCESSING

        // Enable screen curvature.
        //#define CURVATURE

        // Enable 3x oversampling of the beam profile
        #define OVERSAMPLE

        // Use the older, purely gaussian beam profile
        //#define USEGAUSSIAN

        // Macros.
        #define FIX(c) max(abs(c), 1e-5);
        #define PI 3.141592653589

        #ifdef LINEAR_PROCESSING
        #       define TEX2D(c) pow(texture2D(OGL2Texture, (c)), vec4(CRTgamma))
        #else
        #       define TEX2D(c) texture2D(OGL2Texture, (c))
        #endif

        uniform sampler2D OGL2Texture;
        uniform vec4 OGL2Param, OGL2Size;

        vec2 rubyTextureSize = vec2(OGL2Size.x, OGL2Size.y);
        vec2 rubyInputSize = vec2(OGL2Size.x, OGL2Size.y);

        varying vec2 texCoord;
        varying vec2 one;
        varying float mod_factor;

        varying float CRTgamma;
        varying float monitorgamma;

        varying vec2 overscan;
        varying vec2 aspect;

        varying float d;
        varying float R;

        varying float cornersize;
        varying float cornersmooth;

        varying vec3 stretch;
        varying vec2 sinangle;
        varying vec2 cosangle;

        float intersect(vec2 xy)
        {
                float A = dot(xy,xy)+d*d;
                float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
                float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
                return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
        }

        vec2 bkwtrans(vec2 xy)
        {
                float c = intersect(xy);
                vec2 point = vec2(c)*xy;
                point -= vec2(-R)*sinangle;
                point /= vec2(R);
                vec2 tang = sinangle/cosangle;
                vec2 poc = point/cosangle;
                float A = dot(tang,tang)+1.0;
                float B = -2.0*dot(poc,tang);
                float C = dot(poc,poc)-1.0;
                float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
                vec2 uv = (point-a*sinangle)/cosangle;
                float r = FIX(R*acos(a));
                return uv*r/sin(r/R);
        }

        vec2 transform(vec2 coord)
        {
                coord *= rubyTextureSize / rubyInputSize;
                coord = (coord-vec2(0.5))*aspect*stretch.z+stretch.xy;
                return (bkwtrans(coord)/overscan/aspect+vec2(0.5)) * rubyInputSize / rubyTextureSize;
        }

        float corner(vec2 coord)
        {
                coord *= rubyTextureSize / rubyInputSize;
                coord = (coord - vec2(0.5)) * overscan + vec2(0.5);
                coord = min(coord, vec2(1.0)-coord) * aspect;
                vec2 cdist = vec2(cornersize);
                coord = (cdist - min(coord,cdist));
                float dist = sqrt(dot(coord,coord));
                return clamp((cdist.x-dist)*cornersmooth,0.0, 1.0);
        }

        // Calculate the influence of a scanline on the current pixel.
        //
        // 'distance' is the distance in texture coordinates from the current
        // pixel to the scanline in question.
        // 'color' is the colour of the scanline at the horizontal location of
        // the current pixel.
        vec4 scanlineWeights(float distance, vec4 color)
        {
                // "wid" controls the width of the scanline beam, for each RGB
                // channel The "weights" lines basically specify the formula
                // that gives you the profile of the beam, i.e. the intensity as
                // a function of distance from the vertical center of the
                // scanline. In this case, it is gaussian if width=2, and
                // becomes nongaussian for larger widths. Ideally this should
                // be normalized so that the integral across the beam is
                // independent of its width. That is, for a narrower beam
                // "weights" should have a higher peak at the center of the
                // scanline than for a wider beam.
        #ifdef USEGAUSSIAN
                vec4 wid = 0.3 + 0.1 * pow(color, vec4(3.0));
                vec4 weights = vec4(distance / wid);
                return 0.4 * exp(-weights * weights) / wid;
        #else
                vec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0));
                vec4 weights = vec4(distance / 0.3);
                return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
        #endif
        }

        void main()
        {
                // Here's a helpful diagram to keep in mind while trying to
                // understand the code:
                //
                //  |      |      |      |      |
                // -------------------------------
                //  |      |      |      |      |
                //  |  01  |  11  |  21  |  31  | <-- current scanline
                //  |      | @    |      |      |
                // -------------------------------
                //  |      |      |      |      |
                //  |  02  |  12  |  22  |  32  | <-- next scanline
                //  |      |      |      |      |
                // -------------------------------
                //  |      |      |      |      |
                //
                // Each character-cell represents a pixel on the output
                // surface, "@" represents the current pixel (always somewhere
                // in the bottom half of the current scan-line, or the top-half
                // of the next scanline). The grid of lines represents the
                // edges of the texels of the underlying texture.

                // Texture coordinates of the texel containing the active pixel.
        #ifdef CURVATURE
                vec2 xy = transform(texCoord);
        #else
                vec2 xy = texCoord;
        #endif
                float cval = corner(xy);

                // Of all the pixels that are mapped onto the texel we are
                // currently rendering, which pixel are we currently rendering?
                vec2 ratio_scale = xy * rubyTextureSize - vec2(0.5);
        #ifdef OVERSAMPLE
                float filter = fwidth(ratio_scale.y);
        #endif
                vec2 uv_ratio = fract(ratio_scale);

                // Snap to the center of the underlying texel.
                xy = (floor(ratio_scale) + vec2(0.5)) / rubyTextureSize;

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

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

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

                // Normalize.
                coeffs /= dot(coeffs, vec4(1.0));

                // Calculate the effective colour of the current and next
                // scanlines at the horizontal location of the current pixel,
                // using the Lanczos coefficients above.
                vec4 col  = clamp(mat4(
                        TEX2D(xy + vec2(-one.x, 0.0)),
                        TEX2D(xy),
                        TEX2D(xy + vec2(one.x, 0.0)),
                        TEX2D(xy + vec2(2.0 * one.x, 0.0))) * coeffs,
                        0.0, 1.0);
                vec4 col2 = clamp(mat4(
                        TEX2D(xy + vec2(-one.x, one.y)),
                        TEX2D(xy + vec2(0.0, one.y)),
                        TEX2D(xy + one),
                        TEX2D(xy + vec2(2.0 * one.x, one.y))) * coeffs,
                        0.0, 1.0);

        #ifndef LINEAR_PROCESSING
                col  = pow(col , vec4(CRTgamma));
                col2 = pow(col2, vec4(CRTgamma));
        #endif

                // Calculate the influence of the current and next scanlines on
                // the current pixel.
                vec4 weights  = scanlineWeights(uv_ratio.y, col);
                vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
        #ifdef OVERSAMPLE
                uv_ratio.y =uv_ratio.y+1.0/3.0*filter;
                weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;
                weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;
                uv_ratio.y =uv_ratio.y-2.0/3.0*filter;
                weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;
                weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;
        #endif
                vec3 mul_res  = (col * weights + col2 * weights2).rgb * vec3(cval);

                // dot-mask emulation:
                // Output pixels are alternately tinted green and magenta.
                vec3 dotMaskWeights = mix(
                        vec3(1.0, 0.7, 1.0),
                        vec3(0.7, 1.0, 0.7),
                        floor(mod(mod_factor, 2.0))
                    );

                mul_res *= dotMaskWeights;

                // Convert the image gamma for display on our output device.
                mul_res = pow(mul_res, vec3(1.0 / monitorgamma));

                // Color the texel.
                gl_FragColor = vec4(mul_res, 1.0);
        }


Edit 3: Figured out the problem with FFT and DQ7. Apparently FFT switches from a native resolution of 320x224 in the menus to 256x240 during actual gameplay, and DQ7 also appears to use this resolution, and for some reason the shader is unable to deal with this correctly unless you set the resolution to 1020x960, which gets rid of all discoloration. Still not sure what's up with Spyro or Crash, though.

Edit 4: Figured out Spyro. Turns out it uses a veeeeeeeery weird resolution of 512x240, which is then meant to be stretched to a 4:3 ratio. Getting the shader to work with it means manually setting the input size as 512x240 and the output size as 1024x480 on the shader code, then setting the window resolution to 1024x768 and the internal X resolution to 0, although it can be raised to 1 if you change the input size in the code to 1024x240.

Really weird stuff all around. Unless I or someone else can somehow figure out a way to make the shader do all of these things automatically as well as accounting for increasing the internal resolution, this issue of various resolutions is going to necessitate various versions of the shader to account for all these weird resolutions. Already I'm up to four!

[Dieser Beitrag wurde am 29.12.2012 - 10:40 von GPDP aktualisiert]




GPDP 



...

Status:Offline
Date registered: 27.12.2012
Post:5
Send Message
...   Created on 05.01.2013 - 06:39Jump to top Quote this post Report this post Edit Delete


Sorry for the double post, but the previous post was getting way too long, and I have a few new things to share. I'm also hoping someone might be able to help me out with a few things, since my knowledge of coding is, well, extremely limited.

Anyway, I still have not been able to get the shader to handle the various PS1 resolution modes on the fly, although I did somehow find a way to account for changes in internal X resolution through the OGL2 plugin. Here's what I have so far:

gpuPeteOGL2.slf

Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
 
/*
    CRT shader

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

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

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

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

        "Feel free to distribute my shaders under the GPL. After all, the
        barrel distortion code was taken from the Curvature shader, which is
        under the GPL."
    )
*/

        // Comment the next line to disable interpolation in linear gamma (and
        // gain speed).
        #define LINEAR_PROCESSING

        // Enable screen curvature.
        //#define CURVATURE

        // Enable 3x oversampling of the beam profile
        #define OVERSAMPLE

        // Use the older, purely gaussian beam profile
        //#define USEGAUSSIAN

        // Macros.
        #define FIX(c) max(abs(c), 1e-5);
        #define PI 3.141592653589

        #ifdef LINEAR_PROCESSING
        #       define TEX2D(c) pow(texture2D(OGL2Texture, (c)), vec4(CRTgamma))
        #else
        #       define TEX2D(c) texture2D(OGL2Texture, (c))
        #endif

        uniform sampler2D OGL2Texture;
        uniform vec4 OGL2Param, OGL2Size;

        vec2 rubyTextureSize = OGL2Size.xy;
        vec2 rubyInputSize = vec2(OGL2Size.x/3.2, 240.0f);

        varying vec2 texCoord;
        varying vec2 one;
        varying float mod_factor;

        varying float CRTgamma;
        varying float monitorgamma;

        varying vec2 overscan;
        varying vec2 aspect;

        varying float d;
        varying float R;

        varying float cornersize;
        varying float cornersmooth;

        varying vec3 stretch;
        varying vec2 sinangle;
        varying vec2 cosangle;

        float intersect(vec2 xy)
        {
                float A = dot(xy,xy)+d*d;
                float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
                float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
                return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
        }

        vec2 bkwtrans(vec2 xy)
        {
                float c = intersect(xy);
                vec2 point = vec2(c)*xy;
                point -= vec2(-R)*sinangle;
                point /= vec2(R);
                vec2 tang = sinangle/cosangle;
                vec2 poc = point/cosangle;
                float A = dot(tang,tang)+1.0;
                float B = -2.0*dot(poc,tang);
                float C = dot(poc,poc)-1.0;
                float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
                vec2 uv = (point-a*sinangle)/cosangle;
                float r = FIX(R*acos(a));
                return uv*r/sin(r/R);
        }

        vec2 transform(vec2 coord)
        {
                coord *= rubyTextureSize / rubyInputSize;
                coord = (coord-vec2(0.5))*aspect*stretch.z+stretch.xy;
                return (bkwtrans(coord)/overscan/aspect+vec2(0.5)) * rubyInputSize / rubyTextureSize;
        }

        float corner(vec2 coord)
        {
                coord *= rubyTextureSize / rubyInputSize;
                coord = (coord - vec2(0.5)) * overscan + vec2(0.5);
                coord = min(coord, vec2(1.0)-coord) * aspect;
                vec2 cdist = vec2(cornersize);
                coord = (cdist - min(coord,cdist));
                float dist = sqrt(dot(coord,coord));
                return clamp((cdist.x-dist)*cornersmooth,0.0, 1.0);
        }

        // Calculate the influence of a scanline on the current pixel.
        //
        // 'distance' is the distance in texture coordinates from the current
        // pixel to the scanline in question.
        // 'color' is the colour of the scanline at the horizontal location of
        // the current pixel.
        vec4 scanlineWeights(float distance, vec4 color)
        {
                // "wid" controls the width of the scanline beam, for each RGB
                // channel The "weights" lines basically specify the formula
                // that gives you the profile of the beam, i.e. the intensity as
                // a function of distance from the vertical center of the
                // scanline. In this case, it is gaussian if width=2, and
                // becomes nongaussian for larger widths. Ideally this should
                // be normalized so that the integral across the beam is
                // independent of its width. That is, for a narrower beam
                // "weights" should have a higher peak at the center of the
                // scanline than for a wider beam.
        #ifdef USEGAUSSIAN
                vec4 wid = 0.3 + 0.1 * pow(color, vec4(3.0));
                vec4 weights = vec4(distance / wid);
                return 0.4 * exp(-weights * weights) / wid;
        #else
                vec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0));
                vec4 weights = vec4(distance / 0.3);
                return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
        #endif
        }

        void main()
        {
                // Here's a helpful diagram to keep in mind while trying to
                // understand the code:
                //
                //  |      |      |      |      |
                // -------------------------------
                //  |      |      |      |      |
                //  |  01  |  11  |  21  |  31  | <-- current scanline
                //  |      | @    |      |      |
                // -------------------------------
                //  |      |      |      |      |
                //  |  02  |  12  |  22  |  32  | <-- next scanline
                //  |      |      |      |      |
                // -------------------------------
                //  |      |      |      |      |
                //
                // Each character-cell represents a pixel on the output
                // surface, "@" represents the current pixel (always somewhere
                // in the bottom half of the current scan-line, or the top-half
                // of the next scanline). The grid of lines represents the
                // edges of the texels of the underlying texture.

                // Texture coordinates of the texel containing the active pixel.
        #ifdef CURVATURE
                vec2 xy = transform(texCoord);
        #else
                vec2 xy = texCoord;
        #endif
                float cval = corner(xy);

                // Of all the pixels that are mapped onto the texel we are
                // currently rendering, which pixel are we currently rendering?
                vec2 ratio_scale = xy * rubyTextureSize - vec2(0.5);
        #ifdef OVERSAMPLE
                float filter = fwidth(ratio_scale.y);
        #endif
                vec2 uv_ratio = fract(ratio_scale);

                // Snap to the center of the underlying texel.
                xy = (floor(ratio_scale) + vec2(0.5)) / rubyTextureSize;

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

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

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

                // Normalize.
                coeffs /= dot(coeffs, vec4(1.0));

                // Calculate the effective colour of the current and next
                // scanlines at the horizontal location of the current pixel,
                // using the Lanczos coefficients above.
                vec4 col  = clamp(mat4(
                        TEX2D(xy + vec2(-one.x, 0.0)),
                        TEX2D(xy),
                        TEX2D(xy + vec2(one.x, 0.0)),
                        TEX2D(xy + vec2(2.0 * one.x, 0.0))) * coeffs,
                        0.0, 1.0);
                vec4 col2 = clamp(mat4(
                        TEX2D(xy + vec2(-one.x, one.y)),
                        TEX2D(xy + vec2(0.0, one.y)),
                        TEX2D(xy + one),
                        TEX2D(xy + vec2(2.0 * one.x, one.y))) * coeffs,
                        0.0, 1.0);

        #ifndef LINEAR_PROCESSING
                col  = pow(col , vec4(CRTgamma));
                col2 = pow(col2, vec4(CRTgamma));
        #endif

                // Calculate the influence of the current and next scanlines on
                // the current pixel.
                vec4 weights  = scanlineWeights(uv_ratio.y, col);
                vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
        #ifdef OVERSAMPLE
                uv_ratio.y =uv_ratio.y+1.0/3.0*filter;
                weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;
                weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;
                uv_ratio.y =uv_ratio.y-2.0/3.0*filter;
                weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;
                weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;
        #endif
                vec3 mul_res  = (col * weights + col2 * weights2).rgb * vec3(cval);

                // dot-mask emulation:
                // Output pixels are alternately tinted green and magenta.
                vec3 dotMaskWeights = mix(
                        vec3(1.0, 0.7, 1.0),
                        vec3(0.7, 1.0, 0.7),
                        floor(mod(mod_factor, 2.0))
                    );

                mul_res *= dotMaskWeights;

                // Convert the image gamma for display on our output device.
                mul_res = pow(mul_res, vec3(1.0 / monitorgamma));

                // Color the texel.
                gl_FragColor = vec4(mul_res, 1.0);
        }


gpupeteOGL2.slv
Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
 
        varying float CRTgamma;
        varying float monitorgamma;
        varying vec2 overscan;
        varying vec2 aspect;
        varying float d;
        varying float R;
        varying float cornersize;
        varying float cornersmooth;
        varying float res;

        varying vec3 stretch;
        varying vec2 sinangle;
        varying vec2 cosangle;

        uniform vec4 OGL2Param, OGL2Size;

        vec2 rubyTextureSize = OGL2Size.xy;
        vec2 rubyInputSize = vec2(OGL2Size.x/3.2, 240.0f);
        vec2 rubyOutputSize = vec2(1280.0f, 960.0f);

        varying vec2 texCoord;
        varying vec2 one;
        varying float mod_factor;

        #define FIX(c) max(abs(c), 1e-5);

        float intersect(vec2 xy)
        {
                float A = dot(xy,xy)+d*d;
                float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
                float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
                return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
        }

        vec2 bkwtrans(vec2 xy)
        {
                float c = intersect(xy);
                vec2 point = vec2(c)*xy;
                point -= vec2(-R)*sinangle;
                point /= vec2(R);
                vec2 tang = sinangle/cosangle;
                vec2 poc = point/cosangle;
                float A = dot(tang,tang)+1.0;
                float B = -2.0*dot(poc,tang);
                float C = dot(poc,poc)-1.0;
                float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
                vec2 uv = (point-a*sinangle)/cosangle;
                float r = R*acos(a);
                return uv*r/sin(r/R);
        }

        vec2 fwtrans(vec2 uv)
        {
                float r = FIX(sqrt(dot(uv,uv)));
                uv *= sin(r/R)/r;
                float x = 1.0-cos(r/R);
                float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle);
                return d*(uv*cosangle-x*sinangle)/D;
        }

        vec3 maxscale()
        {
                vec2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y));
                vec2 a = vec2(0.5,0.5)*aspect;
                vec2 lo = vec2(fwtrans(vec2(-a.x,c.y)).x,
                             fwtrans(vec2(c.x,-a.y)).y)/aspect;
                vec2 hi = vec2(fwtrans(vec2(+a.x,c.y)).x,
                             fwtrans(vec2(c.x,+a.y)).y)/aspect;
                return vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));
        }


        void main()
        {
                // START of parameters

                // gamma of simulated CRT
                CRTgamma = 2.4;
                // gamma of display monitor (typically 2.2 is correct)
                monitorgamma = 2.2;
                // overscan (e.g. 1.02 for 2% overscan)
                overscan = vec2(0.00,0.00);
                // aspect ratio
                aspect = vec2(1.0, 0.75);
                // lengths are measured in units of (approximately) the width
                // of the monitor simulated distance from viewer to monitor
                d = 2.0;
                // radius of curvature
                R = 1.5;
                // tilt angle in radians
                // (behavior might be a bit wrong if both components are
                // nonzero)
                const vec2 angle = vec2(0.0,-0.15);
                // size of curved corners
                cornersize = 0.001;
                // border smoothness parameter
                // decrease if borders are too aliased
                cornersmooth = 1000.0;

                // END of parameters

                // Do the standard vertex processing.
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

                // Precalculate a bunch of useful values we'll need in the fragment
                // shader.
                sinangle = sin(angle);
                cosangle = cos(angle);
                stretch = maxscale();

                // Texture coords.
                texCoord = gl_MultiTexCoord0.xy;

                // The size of one texel, in texture-coordinates.
                one = 1.0 / rubyTextureSize;

                // Resulting X pixel-coordinate of the pixel we're drawing.
                mod_factor = texCoord.x * rubyTextureSize.x * rubyOutputSize.x / rubyInputSize.x;
        }


This code works for most games that have a native resolution of 320x240. The problem? Not all games run at 320x240. Through a bit of research, I have discovered the PS1 can render at horizontal resolutions of 256, 320, 368, 512, and 640, and vertical resolutions of 240, 256, 480, and 512. While it appears the shader has no problem with any of the vertical resolutions, it is a different story with the horizontal resolution, as it requires knowing the game's specific horizontal resolution for the phosphor emulation. Getting it wrong results in the obvious cyan and magenta vertical lines I talked about earlier.

The problem is, as far as I know there's no way to get the resolution information from the plugin to the shader. The original shader was written for use with RetroArch and BSNES, whose shader spec allows the shader to determine the game's native resolution and adjust accordingly. From what I can see, no such feature is available in Pete's shader spec, or if it exists, I am completely ignorant as to how to code it. As such, I am basically forced to write a separate shader for each resolution mode, which means I have to first find out what resolution a game renders at, then choose the appropriate shader. The code I just shared works for games that natively run at 320x240, and I can increase the internal resolution and it will still work, but other resolutions will break the phosphor emulation.

The key to editing the shader to work with another resolution lies in this line:

vec2 rubyInputSize = vec2(OGL2Size.x/3.2, 240.0f);

What this does is it gets texture size information from OGL2Size, which depends on the internal resolution set by the plugin, then divides it by 3.2 so that you will always get 320. This way no matter what you set for internal X resolution, it will deliver the correct "native" resolution, and phosphor emulation will remain correct. However, you need to divide by a different number for other resolutions. Here are the numbers per resolution:

256x240 - 4
320x240 - 3.2
368x240 - 2.8
512x240 - 2
640x240 - 1.6

So basically, just substitute 3.2 for another one of these numbers depending on your game's native resolution, and the shader will work for that game.

This is where I am requesting help. I would like to make the line look something like this:

vec2 rubyInputSize = vec2(OGL2Size.x/res, 240.0f);

Where "res" is a variable that changes depending on the game's native horizontal resolution. But I have no clue how to get the shader to access that information, as none of the uniforms I've tried seem to have it. If someone more experienced in making shaders could shed some light on this situation, it would be amazing, as it would no longer require keeping around five separate shaders, which would be sort of ok if it wasn't for the fact that some games switch resolutions at times. Chrono Cross, for instance, normally runs at 320x240, but accessing the menu screen makes the game switch to 640x480, which means while using the shader set to work with a 320x240 resolution, the menu screen will be covered in cyan and magenta stripes. It's not the biggest deal, but it's still annoying, and I'd love to have it work right at all times.

Edit: Oh, one more thing. The shader only works with a very specific window resolution, namely that set in the shader through the RubyOutputSize, minus a few pixels since for some reason a couple of visible lines appear if you set the window to exactly the same resolution as in RubyOutputSize. In my code, I have the output resolution as 1280x960, as I like to play at that resolution, but I've found I have to set the window size in the plugin to 1276x960 so there are no lines. If you want to play at, say 640x480, you have to edit the shader, input that resolution, then set the resolution in the plugin to 638x480. This is yet another area where I would like the shader to just work no matter the window resolution, but again, I have no idea how to do so.

Edit 2: One idea that just popped into my head is to somehow take advantage of the "shader levels" in the OGL2 plugin, which if I understand correctly can be implemented through the OGL2Param uniform. Basically, depending on your game's resolution, you would set a different shader level and it would work. So I'm thinking 256, 320, 512, and 640 modes (368 appears to be very rare, so to hell with it) would be levels 1, 2, 3, and 4 respectively. The only problem with this approach is that it would still not account for sudden changes in resolution like the aforementioned Chrono Cross example.

Edit 3: More progress! I have managed to make the emulator always get the correct native resolution for ALL games by changing the following:

vec2 rubyInputSize = vec2(1024.0*OGL2Size.z, 512.0*OGL2Size.w);

This works even in games like Chrono Cross, which changes into another resolution mode in the menus. Also, no more weird vertical lines that require setting a resolution like 1276x960.

The downside? Phosphor emulation gets broken when increasing the internal resolution. If you do not care about increasing the internal resolution, then this shader is almost complete, although I still need to find a way to have it work on all window sizes other than 1280x960 (although I wouldn't recommend having a window size that's not a multiple of 320x240, as it could produce uneven scanlines, but whatever). Still, I'm going to keep trying to see if I can somehow make it account for internal resolution settings.

Edit 4: Never mind, I figured out a way!

vec2 rubyInputSize = vec2(1024.0*OGL2Size.z*(OGL2Param.z+1.0), 512.0*OGL2Size.w*(OGL2Param.z+1.0));

It's kind of ugly, but basically if you want to increase the internal resolution, you have to increase the "shader level" accordingly to make it work. Here's how I have it set up:

Shader level 1 - Native
Shader level 2 - High
Shader level 4 - Very high

Again, it's probably not the most elegant way to go about it, but hell, it works, and with all resolution modes to boot.

The last piece of the puzzle, once again, is the window size, but I'll keep at it.

[Dieser Beitrag wurde am 05.01.2013 - 11:55 von GPDP aktualisiert]




Flamex 



...

Status:Offline
Date registered: 24.08.2010
Post:6
Send Message
...   Created on 06.01.2013 - 01:23Jump to top Quote this post Report this post Edit Delete


Impressive it's the first time i see a scanline effect with dynamic thickness! Just like a real TV




GPDP 



...

Status:Offline
Date registered: 27.12.2012
Post:5
Send Message
...   Created on 06.01.2013 - 02:12Jump to top Quote this post Report this post Edit Delete


Flamex schrieb

    Impressive it's the first time i see a scanline effect with dynamic thickness! Just like a real TV


It is certainly a very impressive shader, and I was very disappointed to see it limited to only BSNES and RetroArch, so I took it upon myself to try and port it despite my limited knowledge. Of course, all credit goes to the original shader's authors, but I am still reserving some pride to myself for figuring out how to get it to work for PS1 emulation outside RetroArch. And I must say it looks a lot better on ePSXe and PCSX-R than it does there, thanks to the GPU plugins' improved pixel blending and shading. Truly the best of both worlds.

Edit: Well, what do you know, it appears the shader made it into the ePSXe shader pack from Emu-France! However, I'm afraid the versions they uploaded aren't the best ones. In case anyone from that site checks back on this thread, this is the best version:

http://www.mediafire.com/download.php?feewfde9uu1jokv

It comes with a regular and wide version of the shader.

[Dieser Beitrag wurde am 07.01.2013 - 13:37 von GPDP aktualisiert]




Lancelot 



...

Status:Offline
Date registered: 21.11.2014
Post:1
Send Message
...   Created on 21.11.2014 - 12:02Jump to top Quote this post Report this post Edit Delete


Hi there!

Just visiting to let you know I've got an error message with the latest version of this shader (yes the one linked just up here);

"Fragment shader(s) failed to link, vertex shader(s) linked"

The first version however (posted on first page of this thread) works fine on my old computer.

(Yes my computer's an old XP laptop with an ATI X1700, and the last OGL update it received is 6.14.10.7659, don't know if this is related.)

Anyway I don't know if it's fixable or definitely hopeless due to my old hardware, but I'd love to experience the final.full version of this shader!

Thanks in advance for your advice/help.




More : [1] [2]

Similarly threads:
Topics Created by Replies Boardname
4-in-1 Shader v1.10 MegaManJuno 3 pete_bernert
Natural Vision Shader + AA Shader v2.o = Best Shader for 2d !! zaykho 16 pete_bernert
xbr shader pmc2 26 pete_bernert
another CRT-TV shader aliaspider -1 pete_bernert
HEAVEN IS REAL BUT SO IS HELL - Der Himmel ist real, die Hölle aber auch loveshalom 0 caeleste_desiderium
Neuer Thread ...





Masthead

This forum is a free service of razyboard.com
Do you want a free forum in less than two minutes? Then click here!



Verwandte Suchbegriffe:
best crt shaders vagrant story retroatch | epsxe best shader emufrance | shader real vagrant | bsnes phosphor 3x uneven | toon shader not working on retroarch | natural vision shader castlevania sotn full settings
blank