Uborder shaders

Ok, updated content_shaders_pack with all those crt shaders converted.

Load the base_presets if you wanna test one by one using M and N keys.

Redundant controls, like curvature, still work in the original crt shaders (i didn’t cut any code) but you should give preference for geom’s curvature.

3 Likes

Hard to keep up with you! :nerd_face:

can’t wait to toy around with the new converted shaders!

here some screens with crt nobody with few prepended shaders and overlays by Duimon:

5 Likes

Don’t worry, I’ll take a break this weekend. I’m a bit tired and need some rest. So I let you with new toys to play.

5 Likes

Hi Hyllian, I just wanna say thanks for this shader. It runs smoothly even on my old Android phone:

I still need to tweak it more, but it’s already way better than the usual black screen :grin:

3 Likes

Nice! This feedback is important, because I didn’t test on mobiles. From your shots, you’re applying over gba games. Do you think some handheld shaders would benefit from using these borders?

Honestly? I’m not really sure anymore. Usually I play GB and GBA using dot shader. This way I could appreciate each pixels properly while still fast enough for my phone:

However after trying them out for a while, I was surprised by how good CRT shaders actually look on handheld games:

While the CRT isn’t as sharp as the LCD, it still looks pretty good nonetheless.

With that said, I don’t mind using the existing CRT shaders for handheld games, but I certainly wouldn’t complain if you decided to port some handheld-specific shaders :slightly_smiling_face:

By the way, regarding Android’ performance, I did notice my phone get hotter and it’s battery is drained faster while using this bezel. However I guess it’s expected since this bezel is way more complicated than a single shader.

1 Like

Wait, is this Mega Bezel default border loaded by uborder?

Maybe you should try the tip from Kokoko3k to halve your fps so that it spare your battery.

Yes, I used a screenshot of the Mega Bezel default border as the background texture for uborder. Here’s what I did:

  1. On my PC, I adjusted the aspect ratio to 20:9 to match my phone’s screen ratio.
  2. Still on my PC, I loaded the Mega Bezel shader and took a screenshot.
  3. Finally, I transferred the screenshot to my phone and followed your tutorial from the post above.

Thanks for the tip, I’ll try it later.

3 Likes

Hi Hyllian and the libretro community,

As this is my first time posting/replying here, if there is anything that I did wrong, please let me know.

Firstly, thank you Hyllian for sharing the this shader. While I don’t use retroarch, I learned about your work while trying to do some post-processing for my own game. Out of all the crt shader that has bezel reflection (I looked at the Mega Bezel, kokoaio), yours was the easiest to understand and easiest to implement in my OpenGL engine.

For the most part, I was able to apply this in the game; however, there’s one part of the ‘uborder-reflections.slang’ shader that I don’t seem to understand fully. So it would be great if you could explain some of the details here:

The reflection for the horizontal and vertical direction is symmetric, so I will just quote a block from the horizontal bezel reflection:

    if((abs(uv.x-0.5) >= (0.5*c_frame.x) && abs(uv.x-0.5) <= (0.5*c_frame.x+bezel_w)) && abs(uv.y-0.5) <= (0.5*c_frame.y+bezel_h))
    {
        uv.x = (uv.x >= 0.50) ? 1.0 + c_frame.x - uv.x + reflection_scr_distance_x : 1.0 - c_frame.x - uv.x - reflection_scr_distance_x;

        reflex.rgb = mix(texture(BlurPass, uv + vec2(bezel_center_x, bezel_center_y)).rgb, vec3(0.0, 1.0, 0.0), params.AdjustView);

        **reflex.rgb = mix(reflex.rgb, frame.rgb, frame.a);**
        reflex.rgb *= (1.0-smoothstep(0.5*c_frame.y-0.1, 0.5*c_frame.y, abs(uv.y-0.5)));

        border.rgb = clamp(border.rgb + reflection_strength*reflex.rgb, 0.0, 1.0);
    }

The bolded part is what I’m confused over. From the images you showcased (and please correct me if I’m wrong), I suppose that the blurred color that is reflected on the bezel is mirror and curved from the main game framebuffer, right? And it seems like the bolded part is not reflecting the main game framebuffer when I was using it.

TLDR: If possible, could you explain where and how in the shader you reflected the main game image on the bezel? I do know that this line uv.x = (uv.x >= 0.50) ? 1.0 + c_frame.x - uv.x + reflection_scr_distance_x : 1.0 - c_frame.x - uv.x - reflection_scr_distance_x; is x-flipping the uv, but it seems to me that this new uv is only applied for the blurred texture, not the main game framebuffer.

Again, thank you, Hyllian, for open-sourcing your work. Attached is a the ported shader that I did.

I’m sorry if I didn’t get the point across clearly, as English is not my native language.

1 Like

Nice, it’s made to be simple, so I’m glad it’s achieving some of its objectives.

Some of my experiments with distinct borders:

The bolded part assures that the reflections only happen outside the game frame. So it put the game above reflections if they overlap. The game alpha channel is used for that task.

About how the reflection is done. I use a mipmapped version of the game framebuffer. I made a simple schematics to explain that:

The reflection part is what need some improvement, as already pointed in this thread. I had to blur the game and then mirror it over the bezel, so I thought about the most easy and fast way to do that by mipmapping the crt output and linearly sampling from that.

But, after some testings, I think the mipmapped framebuffer coordinates aren’t exactly aligned to the crt framebuffer, so the reflections are slightly wrong (you only realizes that if you look carefully to the reflections). I’ll probably rewrite this part using another strategy.

Actually, there’s no bezel in this implementation. Only game, border (background) and reflections. So, the reflections are added to the border. If the reflection overlap with game coordinates, the game takes preference, as I explained earlier. This line adds the reflection to the border:

border.rgb = clamp(border.rgb + reflection_strength*reflex.rgb, 0.0, 1.0);

And the last shader line composes the game frame with the reflected border.

7 Likes

I read through your response multiple times and it definitely helped a lot.

From the shader code, it doesn’t seem obvious to me how you curve the the sampled blurred texture when reflecting on the border.

My hypothesis is that the reflection is not curved at all, but rather is starts a bit early and overlapping with the main game. Maybe that’s why there is a preference check here:

reflex.rgb = mix(reflex.rgb, frame.rgb, frame.a);

Besides, if you look at my attached image from before. You can see that the reflection doesn’t seem to be happening near the corners. I couldn’t figure out why that’s happening tho.

Thanks!

1 Like

I don’t curve the reflection. The blurred texture is already curved, because it’s a mipmapped version of the game framebuffer, and it’s curved by the crt shader. So, your hypothesis is correct, it doesn’t curve, just mirror.

That’s the problem I need to fix. Looks like the mipmapped coordinates are not aligned with the framebuffer ones. No idea why it happens though.

2 Likes

Thanks for the info. I was using a non curved blurred texture hence why it’s kinda different.

As for the missing reflection near the corner. It seems like your version also has the problem too. I think this is because you are mirroring the curved blurred texture, so the corners will be curved in the opposite direction of what you want. This leads to the missing reflection near the corners of the border.

Currently, I’m looking at this shader here (https://www.shadertoy.com/view/lt2SDK) to see how reflection can also be done. It seems pretty straight forward with even less braching on the shader too (so more light weight!)

2 Likes

Thanks for the link. It uses radial coordinates. Looks like a cleaner way to do the maths. I’ll see if I can use some of its ideas to bend the reflections as it’s supposed to be. I doubt it’s more lightweight, though.

It looks like the v220 crt shader in shaders_slang/crt, so it’s already ported to Retroarch.

2 Likes

Yeah, I will try and use some of its parts too and will report back later.

2 Likes

Brief update. I have successfully ported the reflections of the vt220 to my version of uborder and it looks great.

However, there is still an issue in that when you take a look at the grid test, the reflections are not actually curved, so I will probably invest some time into thinking how to fix that. Also, the reflections at the corner are not particularly great as the textures kind of repeats multiple times causing some badness.

Oh Hyllian, if possible could you post a picture of your reflection shader when running the Grid pattern test? If yours is doing the correct thing then I will take another look at your shader code too.

Here are some screenshots of my shaders right now, note that the fps is kind of bad because I haven’t optimized the shaders fully.

1 Like

Nice, where are your code source?

I’ve ported all the code for Retroarch:

I’m thinking about what would be good to get from this. The blur based on random lookups I don’t think is fast enough, so I won’t follow this path. I’m only interested in the reflection coordinates based on roundsquare function, this looks to be the way to go. Now I’m thinking if creating the bezel is a good thing or not. I’d like to know if light code could be used for any other border so that It could create dynamic night versions of the borders.

3 Likes

Sorry for keep you waiting.

Github is notoriously bad for sending binary files so I had to exclude the externals folder from my local SVN repo. This makes building from other Linux environment not possible right now tho.

Anways, the main post-processing shader is in data/shaders. For the crt effect, I use the crt_filter.gl, and the bezel reflection is using the bezel_reflection.gl shader. The code is heavily modified from uborder and various other shaders like mattias, vt220, and some others that I cannot remember the names of.

If there is any part that is not clear to you please let me know. I do acknowledge the overall glsl code is not similar to that in the libretro repo, so feel free to ask away.

Link to the my repo: https://github.com/salaadas/pong-crt

I will try to upload the externals folder for third-party libraries later in case someone wants to build it.

2 Likes

Right now, my current shader code only uses the extra random lookup blur because my blur texture is not blurred enough. But you could take a look at the code with without the #define DO_EXTRA_BLUR.

Later tho, the loop for getting extra blur will go away when I get around to do mipmapping/textureLod for the blur textures. The reason I’m not doing it right now is because my crt filter shader is doing some ghosting from the current texture, and I’m not feeling like messing with it now.

I used the SDF function for getting the flipped-uv and I think it actually helps with the end result.

2 Likes

Nevermind, I won’t try to understand your code. :stuck_out_tongue:

With the code ported to RA, it’s very easy to test params. Now I’m thinking about which things could be useful and adapt to uborder. The code lacks a smooth transition between game frame and the bezel, it needs a corner code. Other thing that I need to figure out is how I turn out the corner on outer border, because I don’t need it rounded. I think there’s some param to reduce corner infinitely. --> https://www.shadertoy.com/view/NdBGRW (RoundRect or Squircle?)

3 Likes