File:Obtaining the inverse function by reflection (small).gif
Summary
Description |
English: This animation shows how to obtain the inverse function's graph visually, by switching the x and y axis, which is equivalent to reflecting the graph across the diagonal. |
Date | |
Source | Own work |
Author | Rodrigo Castro Freibott |
This is the code used to generate the animations. Play around with it on Shadertoy.
GLSL
# define SIZE 5.
# define THICKNESS 0.05
# define AXTHICKNESS 0.0165
# define MARGIN 0.001
# define STARTCHANGE 2.
# define ENDCHANGE 4.
# define STARTFLIP 5.
# define ENDFLIP 7.
# define PI 3.1415926538
float maxcomp(vec2 p)
{
return max(p.x, p.y);
}
float rectangle_sdf(vec2 R, vec2 p)
{
vec2 q = abs(p) - R;
return length(max(q,vec2(0))) + min(maxcomp(q),0.0);
}
vec2 rotate(vec2 p, float angle)
{
vec2 q;
q.x = p.x*cos(angle) - p.y*sin(angle);
q.y = p.x*sin(angle) + p.y*cos(angle);
return q;
}
float xletter_sdf(float size, vec2 centre, vec2 p)
{
vec2 rectangle = vec2(size, size/6.);
p -= centre;
float angle1 = -45.0*PI/180.0;
vec2 q1 = rotate(p, angle1);
float arm1 = rectangle_sdf(rectangle, q1);
float angle2 = 45.0*PI/180.0;
vec2 q2 = rotate(p, angle2);
float arm2 = rectangle_sdf(rectangle, q2);
return min(arm1, arm2);
}
float yletter_sdf(float size, vec2 centre, vec2 p)
{
vec2 rectangle1 = vec2(size, size/6.);
vec2 rectangle2 = vec2(size/3., size/6.);
p -= centre;
// Stand the Y letter upright after flip
if (iTime > (STARTFLIP + ENDFLIP) / 2.)
{
p.x = - p.x;
p.y = - p.y;
}
float angle1 = -45.0*PI/180.0;
vec2 q1 = rotate(p, angle1);
float arm1 = rectangle_sdf(rectangle1, q1);
float angle2 = 45.0*PI/180.0;
vec2 q2 = rotate(p, angle2);
q2 += vec2(size/2., 0.);
float arm2 = rectangle_sdf(rectangle2, q2);
return min(arm1, arm2);
}
vec2 stretch_diagonally(vec2 p, float stretching_amount)
{
/** Returns a vector that corresponds to 'p'
* strecthed (amount>1) or compressed (amount<1) diagonally
* (closer to, or farther away from, the diagonal)
* Actually, the behaviour is the opposite,
* but this is the effect that is seen */
// Change to base {(1/sqrt(2), -1/sqrt(2)), (1/sqrt(2), 1/sqrt(2))}
vec2 q;
q.y = (p.x + p.y) * sqrt(2.)/2.;
q.x = (p.x - p.y) * sqrt(2.)/2.;
// Stretch along the old base's diagonal, or the new base's horizontal
q.x *= 1./stretching_amount;
// Change back to original base {(1, 0), (0, 1)}
vec2 r;
r.x = q.x/sqrt(2.) + q.y/sqrt(2.);
r.y = - q.x/sqrt(2.) + q.y/sqrt(2.);
return r;
}
void paint(inout vec3 col, in vec3 color, in float activation)
{
/** Subtracts from 'col' = vec3(1.) (white) a vector
* so that the color 'color' is given
* to those pixels with 'activation' == 1 */
col -= vec3(1. - color.r, 1. - color.g, 1. - color.b) * activation;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
//// ---- Defining pixel's position ---- ////
vec2 p = SIZE * fragCoord.xy / iResolution.xy; // Coordinates from 0 to SIZE
p -= vec2(SIZE/2., SIZE/2.); // Origin in center
p.x *= iResolution.x/iResolution.y; // x coordinate proportional to width
//// ---- Stretching pixel's position along the diagonal ---- ////
// float stretching_amount = sin(iTime);
float stretching_amount = 2. * (smoothstep(ENDFLIP, STARTFLIP, iTime) - 0.5);
p = stretch_diagonally(p, stretching_amount);
//// ---- Establishing pixel's color ---- ////
vec3 col = vec3(1.); // white background
//// Draw function
float func = sin(p.x); // exp(p.x) OR p.x * p.x OR sin(p.x)
// Function color - transition between red (original function) and blue (its inverse)
vec3 func_color = vec3(
smoothstep(STARTCHANGE, ENDCHANGE, iTime),
0.,
smoothstep(ENDCHANGE, STARTCHANGE, iTime)
);
// Gray for invalid values (e.g. x<0 for sqrt(x), inverse of x^2)
if (p.x < -PI/2. || p.x > PI/2.) func_color = vec3(0.5);
// Give color if pixel's height is between func - THICKNESS and func + THICKNESS
paint(
col,
func_color,
smoothstep(func - THICKNESS, func - THICKNESS + MARGIN, p.y)
* smoothstep(func + THICKNESS + MARGIN, func + THICKNESS, p.y)
);
//// Draw axes
// x axis - same as FUNCTION, but with func = 0.
paint(
col,
vec3(0.), // black
smoothstep(-AXTHICKNESS, -AXTHICKNESS + MARGIN, p.y)
* smoothstep(AXTHICKNESS + MARGIN, AXTHICKNESS, p.y)
);
// y axis - same as x axis, but using width instead of height
paint(
col,
vec3(0.),
smoothstep(-AXTHICKNESS, -AXTHICKNESS + MARGIN, p.x)
* smoothstep(AXTHICKNESS + MARGIN, AXTHICKNESS, p.x)
);
//// Draw X and Y labels
// initial positions
vec2 xpos = vec2(SIZE*0.4, -SIZE*0.075);
vec2 ypos = vec2(-SIZE*0.075, SIZE*0.4);
// x label
vec2 px = p - (ypos - xpos)
* smoothstep(STARTCHANGE, ENDCHANGE, iTime);
float xd = xletter_sdf(SIZE/17.5, xpos, px);
paint(
col,
vec3(0.),
smoothstep(xd, xd + MARGIN, 0.)
);
// y label
vec2 py = p - (xpos - ypos)
* smoothstep(STARTCHANGE, ENDCHANGE, iTime);
float yd = yletter_sdf(SIZE/17.5, ypos, py);
paint(
col,
vec3(0.),
smoothstep(yd, yd + MARGIN, 0.)
);
fragColor = vec4(col.rgb, 1.0);
}
Licensing
I, the copyright holder of this work, hereby publish it under the following license:
This file is licensed under the Creative Commons Attribution-Share Alike 4.0 International license.
- You are free:
- to share – to copy, distribute and transmit the work
- to remix – to adapt the work
- Under the following conditions:
- attribution – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- share alike – If you remix, transform, or build upon the material, you must distribute your contributions under the same or compatible license as the original.