How to conditionally sample a texture in WGSL?

440 views Asked by At

I have a shader with N bind groups for N textures, and I want to sample only one of them at the time in my fragment shader based on a texture index.

Is it possible to do any of the following in WGSL?

  1. Bind each separate texture bind group to an element of an array, so I can access the array
  2. Conditionally sample only one texture. I tried this one as the example below, and I get a validation error. Also it doesn't seem feasible to maintain this approach if I have a lot of textures.
@group(0) @binding(0)
var texture0: texture_2d<f32>;
@group(0) @binding(1)
var sampler0: sampler;
@group(1) @binding(0)
var texture1: texture_2d<f32>;
@group(1) @binding(1)
var sampler1: sampler;

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    var texture_sample: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);
    if (in.texture_index == 1u) {
        texture_sample = textureSample(texture1, sampler1, in.coordinates);
    } else {
        texture_sample = textureSample(texture0, sampler0, in.coordinates);
    }
    return texture_sample;
}

With this I get:

Shader validation error: 
    ┌─ Shader:125:17
    │
125 │         texture_sample = textureSample(texture1, sampler1, in.coordinates);
    │                 ^^^^^^^^^^^^^ naga::Expression [108]
1

There are 1 answers

4
David Huculak On BEST ANSWER

Assuming the naga validation error you're getting is about uniformity, you have three options for making it compile:

  1. Use textureSampleLevel instead of textureSample, which doesn't have the same uniformity requirements
  2. Store your texture index in a uniform variable instead of the vertex output which is a varying value
  3. Perform all the texture samples regardless of branch, and just use the branch to choose which sample you want:
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    let texture_sample_1 = textureSample(texture1, sampler1, in.coordinates);
    let texture_sample_2 = textureSample(texture0, sampler0, in.coordinates);

    var texture_sample: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);
    if (in.texture_index == 1u) {
        texture_sample = texture_sample_1;
    } else {
        texture_sample = texture_sample_2;
    }
    return texture_sample;
}