Radial disclosure of an image in an OpenGL shader

I am playing with the concept of shaders to radially reveal an image using a shader in OpenGL ES. The end goal is to create a circular progress bar by dropping fragments in a slicer that displays a full circular texture of progress.

I have coded my idea here in ShaderToy so you can play with it. I can't seem to get it to work, and since there is no way to debug, I'm having a hard time figuring out why.

Here's my glsl code for the fragment shader:

float magnitude(vec2 vec)
{
    return sqrt((vec.x * vec.x) + (vec.y * vec.y));
}

float angleBetween(vec2 v1, vec2 v2)
{
    return acos(dot(v1, v2) / (magnitude(v1) * magnitude(v2)));
}

float getTargetAngle() 
{
    return clamp(iGlobalTime, 0.0, 360.0);
}

// OpenGL uses upper left as origin by default
bool shouldDrawFragment(vec2 fragCoord)
{
    float targetAngle = getTargetAngle();

    float centerX = iResolution.x / 2.0;
    float centerY = iResolution.y / 2.0;
    vec2 center = vec2(centerX, centerY);

    vec2 up = vec2(centerX, 0.0) - center;
    vec2 v2 = fragCoord - center;

    float angleBetween = angleBetween(up, v2);

    return (angleBetween >= 0.0) && (angleBetween <= targetAngle);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = fragCoord.xy / iResolution.xy;
  if (shouldDrawFragment(fragCoord)) {
    fragColor = texture2D(iChannel0, vec2(uv.x, -uv.y));
  } else {
    fragColor = texture2D(iChannel1, vec2(uv.x, -uv.y));
  }
}

      

It is swept out from the bottom on both sides. I just want it to sweep out of the vector pointing straight up and move clockwise.

+3


source to share


2 answers


Try this code:

const float PI     = 3.1415926;
const float TWO_PI = 6.2831852;

float magnitude(vec2 vec)
{
    return sqrt((vec.x * vec.x) + (vec.y * vec.y));
}

float angleBetween(vec2 v1, vec2 v2)
{
    return atan( v1.x - v2.x, v1.y - v2.y ) + PI;
}

float getTargetAngle() 
{
    return clamp( iGlobalTime, 0.0, TWO_PI );
}

// OpenGL uses upper left as origin by default
bool shouldDrawFragment(vec2 fragCoord)
{
    float targetAngle = getTargetAngle();

    float centerX = iResolution.x / 2.0;
    float centerY = iResolution.y / 2.0;
    vec2 center = vec2(centerX, centerY);

    float a = angleBetween(center, fragCoord );

    return a <= targetAngle;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = fragCoord.xy / iResolution.xy;
  if (shouldDrawFragment(fragCoord)) {
    fragColor = texture2D(iChannel0, vec2(uv.x, -uv.y));
  } else {
    fragColor = texture2D(iChannel1, vec2(uv.x, -uv.y));
  }
}

      

Explanation:

The main change I made was the way I calculate the angle between two vectors:

return atan( v1.x - v2.x, v1.y - v2.y ) + PI;

      

This is the angle of the vector of the difference between v1 and v2. If you swap the x and y values, it changes the direction that angle 0 is, i.e. If you try this:

return atan( v1.y - v2.y, v1.x - v2.x ) + PI;

      

the circle starts from the right, not up. You can also invert the atan value to change the direction of the animation.



You also don't need to worry about the magnification of the vector when calculating the angle between them, note that the code just accepts the angle between the center and current coordinates of the fragment:

float a = angleBetween(center, fragCoord );

      

Other Notes:

Remember, the calculations are in radians, not degrees, so I changed the clamp time (although this does not affect the output):

return clamp( iGlobalTime, 0.0, TWO_PI );

      

You have a variable with the same name as one of your functions:

float angleBetween = angleBetween(up, v2);

      

which should be avoided since not all implementations are happy with it, I was not able to compile your shader on my current machine until I changed this.

+3


source


Change only two functions below



float getTargetAngle() 
{
    return clamp(iGlobalTime, 0.0, 6.14);
}

bool shouldDrawFragment(vec2 fragCoord)
{
    float targetAngle = getTargetAngle();

    float centerX = iResolution.x / 2.0;
    float centerY = iResolution.y / 2.0;
    vec2 center = vec2(centerX, centerY);

    vec2 up = vec2(centerX, 0.0) - center;
    vec2 v2 = fragCoord - center;


  if(fragCoord.x>320.0)// a half width
  {
    up += 2.0*vec2(up.x,-up.y);
    targetAngle *= 2.;
  }
  else  
  {
    up -= 2.0*vec2(up.x,-up.y);
    targetAngle -= 1.57;
  }
    float angleBetween = angleBetween(up, v2);

    return (angleBetween >= 0.0) && (angleBetween <= targetAngle);
}

      

0


source







All Articles