March 28, 2014

Understanding smoothstep

Since I see it used around a lot.

To start off with, here is an image:


Corresponding to this code:
void main(void)
{
vec2 uv = gl_FragCoord.xy / iResolution.xy;
gl_FragColor = vec4(vec3(uv.x),1.0);
}

Pretty self explanatory.  The x value changes consistently throughout the image, from 0.0 to 1.0
And now let's compare that image with the effects of using smoothstep.
Here is using smoothstep in the range of [0.0, 1.0]:

With the code:
void main(void)
{
vec2 uv = gl_FragCoord.xy / iResolution.xy;
float f = (smoothstep( 0.0, 1.0, uv.x) );
gl_FragColor = vec4(vec3(f),1.0);
}

The image is slightly different but it's still pretty even.

But now, let's look at smoothstep in ranges of [0.0, 0.7], [0.0, 0.4], [0.0, 0.1]:


And smoothstep in ranges of [0.3, 1.0], [0.5, 1.0], [0.9, 1.0]

So it's not that smoothstep keeps uv.x within the range of, say, [0.9, 1.0] or the image would be, at its darkest, light grey.  Seems like if uv.x <= 0.9 it'll be set to 0.0 while if uv.x >= 1.0 it'll be set to 1.0.

So this is how you can get a straight line, by interpolating over a very small range of values.
For example, this is smoothstep in range of [0.509, 0.51]:


Here's code that kind of explains it:
void main(void)
{
vec2 uv = gl_FragCoord.xy / iResolution.xy;
float if_below_me_set_to_0 = 0.509;
float if_above_me_set_to_1 = 0.51;
float f = (smoothstep( if_below_me_set_to_0, if_above_me_set_to_1, uv.x) );
gl_FragColor = vec4(vec3(f),1.0);
}

Better variable names would be if_below_me_set_to_0_else_interpolate and if_above_me_set_to_1_else_interpolate but who has time for that

March 25, 2014

Demystifying GLSL

It's useful to know what the values of variables really are.

So, in Shadertoy:

iResolution.x = ~900
iResolution.y = ~500

glFragCoord.x in range of [0, 900]
glFragCoord.y in range of [0, 500]
Represents the current fragment.

Typically a vector uv is used to scale the fragment down.
uv = gl_FragCoord.xy / iResolution.xy
uv.x, uv.y in range of [0, 1]

Then, to put the coordinates in OpenGL normalized device coordinates, I've started using ndc to represent that.
ndc = (uv * 2.0) - 1.0
ndc.x, ndc.y in range of [-1, 1].

Here's a simple program I wrote to explore more GLSL:

void main(void)
{
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec2 ndc = (uv * 2.0 - 1.0);

float line = ndc.y;
float curve = cos(ndc.x);
float movement = cos(iGlobalTime + ndc.x);

float wave = line + curve * movement;

vec3 c = vec3(pow(wave, 0.2));

gl_FragColor = vec4(c, 1.0);
}

If you comment out curve and movement, and set wave to just line, you'll get this picture:

If you uncomment curve and set wave to line + curve, you'll get this:

And uncommenting movement and setting wave to line + curve + movement, it'll animate!

The first time I saw the pow function in someone elses code, I wasn't sure what it did.

It's how you get the line in the picture.
Because this is how (JUST line, no curve or movement) looks without the pow function:

But doing the pow function basically takes the positive half of the image and flips it over the horizontal axis.  This is the result of applying ever smaller values of pow (0.9, 0.5, 0.1):


Which gives us the line shape.

March 24, 2014

GLSL function - mix and clamp

As I peruse shader code written by experts (and novices) I noticed there a ton of functions I don't understand.  Two common ones I see a lot are mix and clamp, and I was really confused about what they did.

I wrote my own mix function, complete with really obvious variable names, so when I get confused again in the future I can look back on this and be like "Oh, that's what that was."

vec4 my_mix(vec4 x, vec4 y, float a) {
vec4 x_contribution = x * (1.0 - a);
vec4 y_contribution = y * a;

return x_contribution + y_contribution;
}

void main(void) {

vec4 white_layer = vec4(1.0, 1.0, 1.0, 1.0);
vec4 black_layer = vec4(0.0, 0.0, 0.0, 1.0);

float amount_of_second_layer = 0.5;

//gl_FragColor = mix(white_layer, black_layer, amount_of_second_layer);
gl_FragColor = my_mix(white_layer, black_layer, amount_of_second_layer);

}

Although I'm having a lot of fun working with this kind of fun and it is so incredibly exciting seeing the possibilities of this, it's also really hard being the n00b.  The absolute n00b.  I look on people's code online and they're like "Oh I'm an absolute beginner at this stuff" and even they are using functions that I've never used before.  It's just been a while since I've been this n00b at something.

But I love it anyway :)

// Edit
The declaration for clamp, vec4 is:
vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal)
How does GLSL judge if x is "bigger" than minVal?  Does it judge solely on magnitude?  Does it compare, component by component?
Answer to my own question, they do it component by component

So here would be code to implement clamp:
vec4 my_clamp(vec4 x, vec4 minVal, vec4 maxVal) {
float x_comp = x.x < minVal.x ? minVal.x : x.x > maxVal.x ? maxVal.x : x.x;
float y_comp = x.y < minVal.y ? minVal.y : x.y > maxVal.y ? maxVal.y : x.y;
float z_comp = x.z < minVal.z ? minVal.z : x.z > maxVal.z ? maxVal.z : x.z;
float w_comp = x.w < minVal.w ? minVal.w : x.w > maxVal.w ? maxVal.w : x.w;

return vec4(x_comp, y_comp, z_comp, w_comp);
}

Ugly code sorry

Noob graphics question

Does graphics programming appreciate good coding practices, like good variable names or refactoring out functionality or short methods?  Or is it so geared towards high performance that all of the good coding practices I've learned doing C# or Java are actually bad?  For trying to learn from other people's code the best approach I've found is refactoring the code until all of the names mean something to me, but when looking on examples at shadertoy.com it seems really common to have magic numbers everywhere, and really large monolithic functions.

March 20, 2014

Fun with #define

At Open Source club today someone mentioned that he uses #define to substitute here_we_go for main.  And say_what for printf.  How brilliant!

So this is what your program could look like:

#define here_we_go main
#define say_what printf

void here_we_go(void) {
   say_what("%s\n", "pretty cool huh!);
}

How fun!

March 19, 2014

Shadertoy

Oh my goodness.  I had no idea the stuff you could do with shaders.


It's possible to code this little guy!  And he moves around and jumps up and stuff and it looks awesome!

I've recently become obsessed with this guy.  And the work he's done with shaders is exactly what I'm trying to accomplish.  I just didn't know it was possible to do this kind of stuff with shaders.

One example:
And the little light specks float around and are magical and everything.  He does a ton of this kind of stuff.  He works for Pixar.  Figures.

Meanwhile this is what I've been working on.  Lolz.

March 17, 2014

Fun with Shaders

Discovered this really cool website where you can play around with OpenGL shaders.

Here's my first shader effect!  Really quite boring compared to some of the examples on there but I like it.

It just fades in and out of colors.  When it comes to graphics it's actually really useful knowing a bit of trig.. I never really saw the use before, but I've used sin and cos to achieve a parabolic effect when simulating a gentle up and down motion, and I've also used them to keep values within the range of 0 and 1.  This sounds really basic to someone experienced with trig/graphics but to someone who never really appreciated its use before, it's really handy to know when coding up simple graphics algorithms.

//Edit
Whoa dang look at this one!  I feel like I'm traveling through someone's arteries.  I can't believe they made that starting with the same base I did.

Or this one.  Feel like I'm traveling through space at light speed.

Or this one - it's like I'm cruising through a velvet desert on the sun on a hovercraft.

Oh goodness I love this one too.  It's like an invisible volcano is shooting up fairy dust.  How did they get the stars to appear?

// Edit March/18/2014
I liked the last one so much I made my own version.  All I did was change the parameters a bit and made the specks a bit fuzzier.  If I randomized them so most of them were blurry but some of them were sharpened, it'd look pretty cool.  Or have different shapes generated.