Author Topic: Rounded corners via glsl shader?  (Read 11350 times)

keilmillerjr

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1167
    • View Profile
Rounded corners via glsl shader?
« on: April 03, 2017, 05:08:03 PM »
Is it possible to pass an image to a shader and create rounded (smooth) corners with transparency? Similar to how border-radius with css works. I have no knowledge at all about how shaders work.

Oomek

  • Administrator
  • Sr. Member
  • *****
  • Posts: 311
  • Radek Dutkiewicz
    • View Profile
    • github.com/oomek
Re: Rounded corners via glsl shader?
« Reply #1 on: April 12, 2017, 04:01:52 AM »
I wrote a little demo for you which adds antialiased rounded corners without using a masking texture. It's aspect ratio agnostic. Have fun with it.

layout.nut
Code: [Select]
local flw = fe.layout.width
local flh = fe.layout.height
local snap_width = 500
local snap_height = 500
local radius = 0

local snap = fe.add_artwork( "snap", 0, 0, snap_width, snap_height )
snap.x = flw / 2
snap.y = flh / 2
snap.origin_x = snap.width / 2
snap.origin_y = snap.height / 2
snap.preserve_aspect_ratio = true

local snap_shader = fe.add_shader( Shader.Fragment, "shader.frag" );
snap.shader = snap_shader

fe.add_ticks_callback( "tick" )

function tick( tick_time ) {
radius += 2
if( radius > 100 ) radius -= 200
snap_shader.set_param( "radius" , radius)
snap_shader.set_param( "snap_dimensions" , snap.width, snap.height)
if ( snap.preserve_aspect_ratio) snap_shader.set_param( "subimg_dimensions" , snap.subimg_width, snap.subimg_height)
else snap_shader.set_param( "subimg_dimensions" , snap.width, snap.height)
}

shader.frag
Code: [Select]
uniform sampler2D texture;
uniform float radius;
uniform vec2 snap_dimensions;
uniform vec2 subimg_dimensions;
vec2 dimensions;

float roundCorners(vec2 p, vec2 b, float r)
{
    return length(max(abs(p)-b+r,0.0))-r;
}

void main()
{
if (subimg_dimensions.x <= subimg_dimensions.y)
{
dimensions.x = snap_dimensions.x * subimg_dimensions.x / subimg_dimensions.y;
dimensions.y = snap_dimensions.y;
}
else
{
dimensions.x = snap_dimensions.x;
dimensions.y = snap_dimensions.y * subimg_dimensions.y / subimg_dimensions.x;
}
    vec2 halfRes = 0.5 * dimensions;
float b = 1.0 - roundCorners(gl_TexCoord[0].xy * dimensions - halfRes, halfRes, abs(radius));
    vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
    gl_FragColor = vec4(gl_Color.xyz * pixel, smoothstep(0.0,1.0,b));
}
« Last Edit: April 13, 2017, 09:54:09 PM by Oomek »

keilmillerjr

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1167
    • View Profile
Re: Rounded corners via glsl shader?
« Reply #2 on: April 15, 2017, 03:54:32 PM »
A huge thank you to Oomek for making this shader, and working with me to resolve a bug using it on my mac. :D

The bug fix was changing the following from/to:
Code: [Select]
gl_FragColor = vec4(gl_Color.xyz * pixel, smoothstep(0.0,1.0,b));
Code: [Select]
gl_FragColor = vec4(gl_Color.xyz * pixel.xyz, smoothstep(0.0,1.0,b));
I added his shader to my shader module with his permission. It might make it a little easier to use it, and being a module means that it can be shared between multiple layouts. You can find it here: https://github.com/keilmillerjr/shader-module

If anyone is using any of my modules or plugins I have been creating lately, please let me know. Feedback would be appreciated, and I will take precaution not to break anything and add version tags on github if changes will cause incompatibility - if people other than myself are using them.

Daniele

  • Newbie
  • *
  • Posts: 1
    • View Profile
Re: Rounded corners via glsl shader?
« Reply #3 on: January 08, 2018, 01:29:14 AM »
I wrote a little demo for you which adds antialiased rounded corners without using a masking texture. It's aspect ratio agnostic. Have fun with it.

layout.nut
Code: [Select]
local flw = fe.layout.width
local flh = fe.layout.height
local snap_width = 500
local snap_height = 500
local radius = 0

local snap = fe.add_artwork( "snap", 0, 0, snap_width, snap_height )
snap.x = flw / 2
snap.y = flh / 2
snap.origin_x = snap.width / 2
snap.origin_y = snap.height / 2
snap.preserve_aspect_ratio = true

local snap_shader = fe.add_shader( Shader.Fragment, "shader.frag" );
snap.shader = snap_shader

fe.add_ticks_callback( "tick" )

function tick( tick_time ) {
radius += 2
if( radius > 100 ) radius -= 200
snap_shader.set_param( "radius" , radius)
snap_shader.set_param( "snap_dimensions" , snap.width, snap.height)
if ( snap.preserve_aspect_ratio) snap_shader.set_param( "subimg_dimensions" , snap.subimg_width, snap.subimg_height)
else snap_shader.set_param( "subimg_dimensions" , snap.width, snap.height)
}

shader.frag
Code: [Select]
uniform sampler2D texture;
uniform float radius;
uniform vec2 snap_dimensions;
uniform vec2 subimg_dimensions;
vec2 dimensions;

float roundCorners(vec2 p, vec2 b, float r)
{
    return length(max(abs(p)-b+r,0.0))-r;
}

void main()
{
if (subimg_dimensions.x <= subimg_dimensions.y)
{
dimensions.x = snap_dimensions.x * subimg_dimensions.x / subimg_dimensions.y;
dimensions.y = snap_dimensions.y;
}
else
{
dimensions.x = snap_dimensions.x;
dimensions.y = snap_dimensions.y * subimg_dimensions.y / subimg_dimensions.x;
}
    vec2 halfRes = 0.5 * dimensions;
float b = 1.0 - roundCorners(gl_TexCoord[0].xy * dimensions - halfRes, halfRes, abs(radius));
    vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
    gl_FragColor = vec4(gl_Color.xyz * pixel, smoothstep(0.0,1.0,b));
}


Your shader is awesome, exactly what I was looking for. Thank a lot!

popoklo

  • Full Member
  • ***
  • Posts: 50
    • View Profile
Re: Rounded corners via glsl shader?
« Reply #4 on: January 13, 2018, 12:39:42 PM »
very great! thanks alot!

oomek! do u also have a drop shadow with blur shader? seems u use this in your new preview theme :)

best greets


jedione

  • Hero Member
  • *****
  • Posts: 1135
  • punktoe
    • View Profile
Re: Rounded corners via glsl shader?
« Reply #5 on: January 13, 2018, 05:52:19 PM »
im not getting round corners.... >:(

not 100% hip to shaders....here is the code using your new module..
and what i get.

Code: [Select]

local flx = fe.layout.width;
local fly = fe.layout.height;
local flw = fe.layout.width;
local flh = fe.layout.height




// Create Artwork Variable
local snap = fe.add_artwork("snap", 0, 0, 640, 480);

// Load Shader Module
if (fe.load_module("shader")) {
  // CrtLottes
  local snapShader = CrtLottes();
 
  // RoundCorners
  if (snap.preserve_aspect_ratio) RoundCorners(100, snap.width, snap.height);
  else RoundCorners(100, snap.width, snap.height, snap.subimg_width, snap.subimg_height);
 
  // Apply the shader to your object
  snap.shader = snapShader.shader;
}




ohh by the way thats a sad face not a mad face....
« Last Edit: January 13, 2018, 05:53:59 PM by jedione »
help a friend....

Oomek

  • Administrator
  • Sr. Member
  • *****
  • Posts: 311
  • Radek Dutkiewicz
    • View Profile
    • github.com/oomek
Re: Rounded corners via glsl shader?
« Reply #6 on: January 13, 2018, 07:41:00 PM »
very great! thanks alot!

oomek! do u also have a drop shadow with blur shader? seems u use this in your new preview theme :)

best greets

No, it's just a png behind the snaps, but I'm thinking about making it in the shader. The principle is the same as for the blur.

Oomek

  • Administrator
  • Sr. Member
  • *****
  • Posts: 311
  • Radek Dutkiewicz
    • View Profile
    • github.com/oomek
Re: Rounded corners via glsl shader?
« Reply #7 on: January 13, 2018, 07:44:03 PM »
im not getting round corners.... >:(

not 100% hip to shaders....here is the code using your new module..
and what i get.

You cannot add 2 shaders to one object unfortunately. You would need to combine them, or apply a second shader to a surface on which you have drawn the first object with the scanlines.