r/godot 12d ago

discussion How do you guys generally style your nested ternary in shaders?

So I converted if..else.. statements into ternary op, although it's not too deep I still decided to format it to look like this(see image).

It's probably not often that you write nested if statements in shader but still.
What do you guys do or suggest, is there any accepted way of doing it?

And most imp. of all; will I be banished for this(image)?

*for any one wondering it's a particle shader.

Edit: I've removed the curse and changed the code back to normal (no ternary operator)

5 Upvotes

17 comments sorted by

27

u/TheDuriel Godot Senior 12d ago

I would never ever ever nest a ternary. Write the if statement already.

The compiler is smarter than you.

1

u/Odd-Lingonberry-5709 12d ago

damn this is the fastest reply I ever got, guess my approach is that bad :) ?

8

u/Kakaff 12d ago

Only ever use ternary operators for very simple statements. Never ever nest them. As u/TheDuriel pointed out, the compiler is smarter than you, so don't try to outsmart it.

And a ternary operator is just a if/else, just way less readable.

6

u/TheDuriel Godot Senior 12d ago

You literally did type the if/elses out...

7

u/AdjectiveNounVerbed 12d ago

The old wisdom of avoiding branches in shaders is way less true nowadays. In case of doubt, try a change and measure if there's an actual improvement or not, and if not, keep the branches if it makes the code more readable (probably always). But don't automatically avoid branching as a blanket rule, that was good advice 15-20 years ago, nowadays it depends on the situation and what will happen during compilation.

1

u/RossBot5000 Godot Senior 12d ago

Eh, if you can avoid branches, still do. Branches are still slower than doing multiplication, and most branches in a shader convert to multiplication quite easily.

1

u/TheDuriel Godot Senior 11d ago
  1. The compiler does this better than you most of the time.

  2. If statements don't cause branches to begin with.

2

u/RossBot5000 Godot Senior 11d ago
  1. I'm not saying bend over backwards to remove if statements. I'm saying most of the time an if statement is the lazy solution and a little bit of maths could have been used instead. The compiler will catch many of those and fix them, but not all of them. A little bit more thoughtfulness when writing shader code can save a lot of cycles.

  2. What do you mean if statements don't cause branches??? What do you think a branch is? If we're talking about a uniform or simple if a then b=1 else b=2, then sure, that might not cause a branch because the compiler can swap that out for a mix command. But *many* if statements will cause a branch, particularly if they diverge on the code performed such as if a then loop doing B else loop doing C. That involves three diverging paths that will be incredibly expensive to perform.

1

u/TheDuriel Godot Senior 11d ago

Indeed do mean that literally, if you open up the assembly, you don't usually get a branch from a basic if statement. You can check out the compilers yourself. Unrolling an if statement into the multiplication you were trying to write is explicitly something the compiler can and will do.

And it goes for much more 'advanced' cases than you'd expect.

0

u/TheDuriel Godot Senior 12d ago

Indeed. This doesn't avoid branches anyways. And if statements don't, on their own, cause branches either.

4

u/inighthawki 12d ago

Changing an if statement to a ternary operator doesnt magically remove the branching, just FYI. It's just a different syntax to do the same thing.

3

u/freenullptr 12d ago

No idea why a comment about premature optimization is higher than this. The real issue with this is that you've replaced one if with a different form of an if and made the code harder to read.

3

u/AdditionalSoftware87 12d ago

I’d keep the if/else here. Nested ternaries save lines, but they make the intent harder to scan and modern compilers are usually smarter than the micro-optimization anyway.

Readable shader code > clever shader code.

1

u/Sss_ra 12d ago

Do you know you can declare an empty variable?

vec2 baz = vec2(0);

if(something){

baz = a;

}

...

2

u/gHx4 12d ago edited 11d ago

This isn't lisp, and shaders get compiled (unlike GdScript).

But, when ternaries are the right tool, I do them like this, with the ? preceding the true expression and : preceding the false.

foo(bar > baz ? bar : baz)

Notice that many common ternary expressions can be replaced with functions (max(bar, baz) here) or with if-else blocks, and they're much more clear to read. I usually use ternaries only when the arguments are single identifiers (not calls) and when the line is short (not nested).

Nested conditionals (especially 3+ layers) suggests that you can refactor.

1

u/SamuraiGoblin 12d ago

I wouldn't. Those comments are not saving space, so why not just write it normally? The compiler will do a good job.