• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Shaders [solved]Shader pow function

jf_knight

Member
I'm working on a shader that contains the line:

Code:
float s = mix(r.x, (sin((iTime * 2.5 + 60.0) * r.y) * 0.5 + 0.5) * ((r.y * r.y) * (r.y * r.y)), 0.04);
color += pow(s, 70.0) * (1.0 - v);
When I try to compile, it gives me an error saying I should use abs on the "s" variable because the base of the pow function, "s", must never be negative though I need the negative value so I can complete the effect the shader is supposed to perform. I've tried it with abs(s) and it compiles and runs, but it does not look how its supped to. GML's "power" function does not work in "fragment either.
I tried using an if/else if conditional hoping to get the same values;

Code:
 if (s < 0.0)
{
    color += (pow(abs(s), 70.0) * (1.0 - v)) * -1.0;
}
else if (s > 0.0)
{
    color += pow(abs(s), 70.0) * (1.0 - v);
}
but shaders don't necessarily "loop" and just defaults to whatever the value of s was on the initial run, plus I read on here that shaders are not supposed to have conditionals anyway.

If this line of code works on shadertoy.com, should it not work on gamemaker as well?
Should I try writing my own power function from scratch?
Is there another way around this?
 

Binsk

Member
GML's "power" function does not work in "fragment either.
That would make sense as shaders do not use GML. They are programs for your GPU and need to be in very specific languages (GLSL, HLSL, etc) because, unlike the rest of your game, the shader is compiled at runtime specifically for the GPU. That in mind, you should rather look for functions supported by your shader language and not GML.

I am assuming you are using GLSL ES which should support pow for all versions and I believe in both vertex and fragment shaders.

but shaders don't necessarily "loop" and just defaults to whatever the value of s was on the initial run
If by "initial run" you mean the first time you submit a request to the GPU, then that is incorrect. If you mean "initial run" as in the first fragment that is computed then yes, that is true. Assuming this is in the fragment shader then your code will be executed once for every pixel being render, much of that being in parallel (unlike your CPU-based code in GameMaker).

plus I read on here that shaders are not supposed to have conditionals anyway.
Eh, you can get away with it. Especially with the kind of calculation you are doing. To keep it simple, basically everything in both sides of the if statement will be calculated while only keeping the result of the correct one. This means if you are trying to skip lots of extra math with an IF statement in a shader, then it will still be calculated anyway even if unused. This, of course, unless the statement is only checking uniforms or constants (which the compiler will optimize and it becomes a non-issue).

Honestly, you are perfectly fine with the if statement here. If you really don't like it then use the sign function:
Code:
olor += (pow(abs(s), 70.0) * (1.0 - v)) * sign(s);
 
Top