Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A shader that sets transparancy

This thread is locked; no one can reply to it. rss feed Print
A shader that sets transparancy
A. van Patmos
Member #15,349
October 2013

I'd like to use a shader to find out if vertices are inside a circle. If not make the vertex transparant. The following compiles and runs but simply shows the full image as I made it.

#SelectExpand
1// Fragment 2#version 420 3uniform sampler2D tex; // used texture unit 4varying vec2 v_texCoord; // x,y coordinates of point tested 5uniform float mx, my; // x,y coordinates of circle's centre 6 7// (x-mx)2+(y-my)2=r2 - points on circle 8// x2 - 2mx*x + mx2 + y2 - 2my*y + my2 = r2 - rewritten 9 10float Cirkel( vec2 p, float mx, float my ) 11{ 12// radius is 23px, r squared is 529 13 if(pow(p.x, 2) - 2*mx*p.x + pow(mx, 2) + pow(p.y, 2) - 2*my*p.y + pow(my, 2) < 529) 14 return 1.0; 15 else 16 return 0.0; 17} 18 19void main() 20{ 21 gl_FragColor = texture2D(tex, v_texCoord); 22 gl_FragColor.a = Cirkel(v_texCoord, mx, my); 23}

and

// Vertex
#version 420
varying vec2 v_texCoord;

void main()
{
    v_texCoord = gl_MultiTexCoord0;// * 0.5;// kleinere factor vergroot meer
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

Is this any good at all? Is it possible to use a mask image (white circle in black square) and let a shader do the filling in of the .a component?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Dizzy Egg
Member #10,824
March 2009
avatar

This is the shader I use to achieve what you are asking for, but it's an Allegro shader not a pure openGl one - the circle function may be some help though:

#SelectExpand
1uniform sampler2D al_tex; 2varying vec4 varying_color; 3varying vec2 varying_texcoord; 4 5vec4 pixel; 6 7 8float circle(in vec2 coord, in float r){ 9 vec2 dist = coord - vec2(0.5); 10 return 1.-smoothstep(r - (r * 0.01), r + (r * 0.01), dot(dist, dist) * 4.0); 11} 12 13void main() 14{ 15 pixel = texture2D(al_tex, varying_texcoord); 16 pixel.a = circle(varying_texcoord, 0.9); 17 18 if(pixel.a == 0) { 19 pixel.r = 0; 20 pixel.g = 0; 21 pixel.b = 0; 22 } 23 24 gl_FragColor = pixel; 25}

This will draw a circle in a bitmap of any size, with the other pixels transparent.

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

A. van Patmos
Member #15,349
October 2013

The backbuffer alpha should be known and filled already I think. I have this:

  wtr = al_load_bitmap("data/voor.bmp");
  tmp = al_create_bitmap(al_get_bitmap_width(wtr)*2, al_get_bitmap_height(wtr)*2);

and

#SelectExpand
1while (1) 2{ 3 al_wait_for_event(event_queue, &ev); 4 5 ALLEGRO_KEYBOARD_STATE s; 6 al_get_keyboard_state(&s); 7 if (al_key_down(&s, ALLEGRO_KEY_F8)) 8 break; 9 10 al_set_target_bitmap(tmp); 11 al_use_shader(kijker); 12 al_set_shader_sampler("tex", wtr, 0); 13 al_set_shader_float("x" , x); 14 al_set_shader_float("y" , y); 15 al_draw_scaled_bitmap(wtr, 0, 0, al_get_bitmap_width(wtr), al_get_bitmap_height(wtr), 0, 0, al_get_bitmap_width(tmp), al_get_bitmap_height(tmp), 0); 16 al_use_shader(NULL); 17 18 al_set_target_backbuffer(display); 19 al_clear_to_color(al_map_rgb(215, 255, 255)); 20 al_draw_bitmap(achtergrond, 64, 64, 0); 21 al_draw_bitmap(tmp, 120, 120, 0); 22 al_flip_display(); 23 24 al_rest(0.01); 25}

I didn't occur to me to post this code. So wtr goes to the shader and it's result will be written to a four times larger bitmap tmp (yes, simulating a scope).

I'll try Dizzy Eggs function for sure but I'd like to know what I'm doing wrong.

- And it does the resize OK, but draws the full square.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

>The backbuffer alpha should be known and filled already I think. I have this:

No, it's not defined. The backbuffer may or may not have alpha, depending on the driver and how you set it up, so you can't draw alpha directly to the backbuffer and expect it to work.

Dizzy Egg
Member #10,824
March 2009
avatar

You need to respect that the coordinates are 1.0/1.0 for the image in openGl, so you should probably use something like this (this assumes that wtr is 23x23 and tmp is 46x46):

float Cirkel( vec2 p, float mx, float my )
{
  // mx and my will be 23,23 the centre of tmp
  p.x *= 46; //multiply by the size of tmp
  p.y *= 46; //multiply by the size of tmp
  p.y = 46-p.y; //offset for openGl coords

  if(pow(p.x, 2) - 2*mx*p.x + pow(mx, 2) + pow(p.y, 2) - 2*my*p.y + pow(my, 2) < 529)
    return 1.0;
  else
    return 0.0;
}

You always want to multiply p.x and p.y by the size of tmp, and set mx and my to the centre of tmp...

EDIT:

Also, make sure you set:

al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);

Before drawing, to make sure alpha will work properly with the shader.

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

A. van Patmos
Member #15,349
October 2013

I already had al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); before Edgar's second reply but forgot to post that.

And I had done al_get_bitmap_format(al_get_target_bitmap() which reports 9, it is ALLEGRO_PIXEL_FORMAT_ARGB_8888 if read it right. It creates a bigger cirkle now always on a 93x93 bitmap.

float Cirkel( vec2 p)//, float mx, float my )
{
  // mx and my will be 46.5,46.5 the centre of tmp, radius too is 46.5
  p.x *= 93; //multiply by the size of tmp
  p.y *= 93; //multiply by the size of tmp
  p.y = 93-p.y; //offset for openGl coords

//if(pow(p.x, 2) - 2*mx*p.x + pow(mx, 2) + pow(p.y, 2) - 2*my*p.y + pow(my, 2) < 529)
  if(pow(p.x, 2) -   93*p.x              + pow(p.y, 2) -   93*p.y              < -2162.25)
    return 1.0;
  else
    return 0.01;
}

But this is a great function, thanks. I can feed it a smaller image for more magnification.

-edit: I redid the whole thing in a simpler program, now paying attention to do an al_clear_to_color(al_map_rgba_f(0.0, 0.0, 0.0, 0.0)); after setting tmp as target. That did it.

Go to: