Page 1 of 1

CRT effect and shaders:

Posted: Sat Sep 15, 2018 1:07 am
by pestocat
So last year this game "Stray" was made for the love2d jam. It has really cool graphics and I was wondering if anyone has some Ideas on how to recreate the effects. I've been reading up on shaders a little bit and was thinking maybe that's how it works, what do you guys think?

Specifically the effects I would like to recreate are:

1. The bulging crt effect
I was thinking that this one may have been acheived like this:
The game is drawn to the screen normally, in a big perfect square, then a shader picks up each pixel and moves it to where it ought to be to make the bulging effect. What kind of logic would make that happen though? I could see moving each pixel closer to a corresponding set of points on x = y and x = -y lines, but idk.


2. This interesting color separation, it seems like the red and blue are offset a little bit.
I was thinking this might have something to do with red and blue values being relates to the x position on the screen (as you see the effect is mush more pronounces to the right) but it must be more complicated than that alone, because that would yield a sort of gradient look which is not what is seen here.

Thanks, I hope I was specific enough.

Re: CRT effect and shaders:

Posted: Sat Sep 15, 2018 2:11 am
by zorg
You can check this out: https://github.com/vrld/moonshine
Also that effect has a name, it's called Chromatic Aberration.

Re: CRT effect and shaders:

Posted: Sat Sep 15, 2018 3:12 am
by pestocat
Thank you zorg, will check out moonshine.

I was also able to find the actual shader from the game, messed around with it and it created some great effects, but my main goal here is to really understand what it is doing and how.
If anyone can see it in the code and explain it more plainly that would be much appreciated.


Code: Select all

extern float elapsed = 10;

vec2 radialDistortion(vec2 coord, float dist) {
  vec2 cc = coord - 0.5;
  dist = dot(cc, cc) * dist + cos(elapsed * .3) * .01;
  return (coord + cc * (1.0 + dist) * dist);
}


vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc) {
  vec2 tcr = radialDistortion(tc, .24)  + vec2(.001, 0);
  vec2 tcg = radialDistortion(tc, .20);
  vec2 tcb = radialDistortion(tc, .18) - vec2(.001, 0);
  vec4 res = vec4(Texel(tex, tcr).r, Texel(tex, tcg).g, Texel(tex, tcb).b, 1)
    - cos(tcg.y * 128. * 3.142 * 2) * .03
    - sin(tcg.x * 128. * 3.142 * 2) * .03;
  return res * Texel(tex, tcg).a;
}

Re: CRT effect and shaders:

Posted: Sat Sep 15, 2018 4:10 am
by zorg
the crt effect is basically all that code, and the part that makes the red and blue channels be offset (not simply just "to the left/right" but radially outward and inward from the given coordinates, are these parts:

vec2 tcr = radialDistortion(tc, .24) + vec2(.001, 0);
vec2 tcg = radialDistortion(tc, .20);
vec2 tcb = radialDistortion(tc, .18) - vec2(.001, 0);

Re: CRT effect and shaders:

Posted: Sat Sep 15, 2018 9:06 am
by pgimeno
A key to understand shaders is that they don't say "where each pixel should move", but "what each pixel should show". It's kind of the other way around. For example, if you want to show an image tilted 30° to the right, the shader has to sample the original image with an angle of 30° to the left.

Re: CRT effect and shaders:

Posted: Sat Sep 15, 2018 9:49 am
by ivan
I use both of these effects in one of my games:
https://store.steampowered.com/app/2878 ... _Commando/
The trick is to render everything to canvas first.
There are more things you can do in addition to chromatic aberration and curving the screen.

Code: Select all

// jangsy5 code
extern number distortion = 0.1;
extern number aberration = 2.0;
vec4 effect(vec4 color, Image tx, vec2 tc, vec2 pc)
{
  // curvature
  vec2 cc = tc - 0.5f;
  float dist = dot(cc, cc)*distortion;
  tc = (tc + cc * (1.0f + dist) * dist);

  // fake chromatic aberration
  float sx = aberration/love_ScreenSize.x;
  float sy = aberration/love_ScreenSize.y;
  vec4 r = Texel(tx, vec2(tc.x + sx, tc.y - sy));
  vec4 g = Texel(tx, vec2(tc.x, tc.y + sy));
  vec4 b = Texel(tx, vec2(tc.x - sx, tc.y - sy));
  number a = (r.a + g.a + b.a)/3.0;

  return vec4(r.r, g.g, b.b, a);
}

Re: CRT effect and shaders:

Posted: Tue Sep 18, 2018 4:22 am
by pestocat
Thanks everyone for the replies! Very helpful, starting to get my head around the whole shaders thing...

Re: CRT effect and shaders:

Posted: Mon Jul 27, 2020 4:57 am
by inJuly
pestocat wrote: Sat Sep 15, 2018 3:12 am Thank you zorg, will check out moonshine.

I was also able to find the actual shader from the game, messed around with it and it created some great effects, but my main goal here is to really understand what it is doing and how.
If anyone can see it in the code and explain it more plainly that would be much appreciated.


Code: Select all

extern float elapsed = 10;

vec2 radialDistortion(vec2 coord, float dist) {
  vec2 cc = coord - 0.5;
  dist = dot(cc, cc) * dist + cos(elapsed * .3) * .01;
  return (coord + cc * (1.0 + dist) * dist);
}


vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc) {
  vec2 tcr = radialDistortion(tc, .24)  + vec2(.001, 0);
  vec2 tcg = radialDistortion(tc, .20);
  vec2 tcb = radialDistortion(tc, .18) - vec2(.001, 0);
  vec4 res = vec4(Texel(tex, tcr).r, Texel(tex, tcg).g, Texel(tex, tcb).b, 1)
    - cos(tcg.y * 128. * 3.142 * 2) * .03
    - sin(tcg.x * 128. * 3.142 * 2) * .03;
  return res * Texel(tex, tcg).a;
}
Don't know if you'll see a 2 year old post but, where did you get the actual shader used in the game ?

Re: CRT effect and shaders:

Posted: Mon Jul 27, 2020 7:57 am
by zorg
inJuly wrote: Mon Jul 27, 2020 4:57 am
pestocat wrote: Sat Sep 15, 2018 3:12 am Thank you zorg, will check out moonshine.

I was also able to find the actual shader from the game, messed around with it and it created some great effects, but my main goal here is to really understand what it is doing and how.
If anyone can see it in the code and explain it more plainly that would be much appreciated.


Code: Select all

extern float elapsed = 10;

vec2 radialDistortion(vec2 coord, float dist) {
  vec2 cc = coord - 0.5;
  dist = dot(cc, cc) * dist + cos(elapsed * .3) * .01;
  return (coord + cc * (1.0 + dist) * dist);
}


vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc) {
  vec2 tcr = radialDistortion(tc, .24)  + vec2(.001, 0);
  vec2 tcg = radialDistortion(tc, .20);
  vec2 tcb = radialDistortion(tc, .18) - vec2(.001, 0);
  vec4 res = vec4(Texel(tex, tcr).r, Texel(tex, tcg).g, Texel(tex, tcb).b, 1)
    - cos(tcg.y * 128. * 3.142 * 2) * .03
    - sin(tcg.x * 128. * 3.142 * 2) * .03;
  return res * Texel(tex, tcg).a;
}
Don't know if you'll see a 2 year old post but, where did you get the actual shader used in the game ?
They probably just got the game from the jam page, and unzipped it... you do realize löve games are (usually) not compiled.

Re: CRT effect and shaders:

Posted: Mon Jul 27, 2020 1:40 pm
by inJuly
zorg wrote: Mon Jul 27, 2020 7:57 am
inJuly wrote: Mon Jul 27, 2020 4:57 am
pestocat wrote: Sat Sep 15, 2018 3:12 am Thank you zorg, will check out moonshine.

I was also able to find the actual shader from the game, messed around with it and it created some great effects, but my main goal here is to really understand what it is doing and how.
If anyone can see it in the code and explain it more plainly that would be much appreciated.


Code: Select all

extern float elapsed = 10;

vec2 radialDistortion(vec2 coord, float dist) {
  vec2 cc = coord - 0.5;
  dist = dot(cc, cc) * dist + cos(elapsed * .3) * .01;
  return (coord + cc * (1.0 + dist) * dist);
}


vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc) {
  vec2 tcr = radialDistortion(tc, .24)  + vec2(.001, 0);
  vec2 tcg = radialDistortion(tc, .20);
  vec2 tcb = radialDistortion(tc, .18) - vec2(.001, 0);
  vec4 res = vec4(Texel(tex, tcr).r, Texel(tex, tcg).g, Texel(tex, tcb).b, 1)
    - cos(tcg.y * 128. * 3.142 * 2) * .03
    - sin(tcg.x * 128. * 3.142 * 2) * .03;
  return res * Texel(tex, tcg).a;
}
Don't know if you'll see a 2 year old post but, where did you get the actual shader used in the game ?
They probably just got the game from the jam page, and unzipped it... you do realize löve games are (usually) not compiled.
rxi's games are usually Lua-ced so that would be extremely difficult...