Does TSL Switch works?

I’m migrating a GLSL shader to TSL where I need a Switch statement to select a texture from an array. Playing around I think the Switch function is broken.
This is the code:

// Simple uv.x animation

const {vec4, Switch, uv, int, min } = await import( ‘three/tsl’ );

const uv0 = uv();
const index = min(uv0.x.mul(5).toInt(), 5);
const result = Switch(index)
.Default(() => { return vec4(0, 1, 1, 1); })
.Case(int(0), () => { return vec4(1, 0, 0, 1); })
.Case(int(1), () => { return vec4(0, 0, 1, 1); })
.Case(int(2), () => { return vec4(0, 1, 0, 1); })
.Case(int(3), () => { return vec4(1, 0, 1, 1); })
.Case(int(4), () => { return vec4(1, 1, 0, 1); })

output = result;

and you can test it here:

The resulting shader is obviously wrong.

Looks like it might be related to how the index is computed. Since min(uv0.x.mul(5).toInt(), 5) can return 5, but you only define cases 0–4, the switch might be hitting the default path or generating odd code in the transpiled shader.

You could try clamping it to 4 instead:

const index = min(uv0.x.mul(5).toInt(), 4);

Also worth checking the generated shader code to see how TSL expands the Switch. Sometimes these constructs end up being translated into chained conditionals rather than an actual switch, which can expose edge cases.

If the goal is selecting a texture from an array, another workaround might be using chained select or mix operations based on comparisons, since those tend to compile more predictably in node systems.

Not only the Switch doesn’t work but also the If. This is the r183

const {vec4, If, uv, int, min } = await import( ‘three/tsl’ );

const uv0 = uv();
const index = min(uv0.x.mul(5).toInt(), 5);
const result = vec4(0,0,0,1);
If(index.equal(0), () => result.assign(vec4(0, 1, 0, 1)))
.ElseIf(index.equal(1), () => result.assign(vec4(1, 0, 0, 1)))
.ElseIf(index.equal(2), () => result.assign(vec4(0, 0, 1, 1)))
.ElseIf(index.equal(3), () => result.assign(vec4(0, 1, 0, 1)))
.ElseIf(index.equal(4), () => result.assign(vec4(1, 0, 1, 1)))
.Else(() => result.assign(vec4(1, 1, 0, 1)))

output = result;

I don’t know how but sometimes I got an output where there are way too many if else in the shader.

but ternary does work.

const {vec4, select, uv, int, min } = await import( ‘three/tsl’ );

const uv0 = uv();
const index = min(uv0.x.mul(5).toInt(), 5);
const result = select(index.equal(0), vec4(0, 1, 0, 1),
select(index.equal(1), vec4(1,0,0,1),
select(index.equal(2), vec4(0,0,1,1),
select(index.equal(3), vec4(0,1,0,1),
select(index.equal(4), vec4(1,0,1,1),
vec4(1,1,0,1)
)))));

output = result;

Switch works fine. Try in a standalone file, not in the TSL editor.

https://codepen.io/boytchev/pen/WbGrbvp?editors=0010

image

2 Likes

Thanks, that gives something to look at. And… okey looking more comments and debugging the example, as you mention, they works fine, but only if they are inside a Fn. Not sure if this is a mandatory constraint but okey.