2
$\begingroup$

I was working through https://thebookofshaders.com/05/ when I came across some unintuitive behaviour of smoothstep. I wanted to understand it better so I replaced the following line of code:

return smoothstep(0.02, 0.0, abs(st.y - st.x));

With all arguments as float literals:

return smoothstep(0.02, 0.0, 0.0);

I was expecting smoothstep to return 1.0 but instead it seems to always return 0.0 regardless of the value of the third argument. If instead of that you use a float variable:

float temp = 0.0;
return smoothstep(0.02, 0.0, temp);

It works as expected and returns 1.0. Why is this? I assume this is documented somewhere though it's not obvious what to search for.

Minimal, Reproducible Example:

#ifdef GL_ES
precision mediump float;
#endif

void main() {
    float diff = 0.0;
    float green = smoothstep(0.2, 0.0, diff);
    // Won't result in green if uncommented
    // green = smoothstep(0.2, 0.0, 0.0);

    gl_FragColor = vec4(0.0, green, 0.0, 1.0);
}
```
$\endgroup$

2 Answers 2

4
$\begingroup$

Undefined behavior is undefined. smoothstep requires that the first argument is less than the second. If that is not the case, undefined behavior results.

$\endgroup$
2
  • $\begingroup$ Thank you. I wonder why the code works when smoothstep is called with (0.2, 0.0, abs(st.y - st.x)) but not when it's called with all literals e.g. (0.2, 0.0, 0.1). It does work when it's called with all literals and edge0 < edge 1, e.g. (0.0, 0.2, 0.1) but I wonder why a literal different from a variable? $\endgroup$
    – AJP
    Jan 10 at 14:49
  • $\begingroup$ @AJP: Undefined behavior is undefined; that means anything can happen, including contradictory things. Maybe the constant expression evaluator in the compiler detected the UB and gave one result, while the runtime version delivered a different one. What does it matter? It'll be different for different compilers because the code itself is dysfunctional. $\endgroup$ Jan 10 at 14:51
0
$\begingroup$

A general answer is that behavior can be different using consts (i.e. solved at compile time) or variables (i.e. solved at runtime), because these are treated by 2 absolutely different engines. The GLSL spec is very lazy in terms of compulsory behaviors, but I observed that the worst is often when relying to early evaluation of functions (i.e. all const parameters), e.g. in term of IEEE754 compliance, behavior for swapped parameters, etc. Note also that despite some out-of-spec situations often work correctly ( i.e. as expected ), it can be very OS, GPU or browser dependant.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.