Search code examples
unity-game-engineglslshadergpucg

Fastest way to write sampler2D * 0 and sampler2D * 1 to add many together? (glsl/cg)


I would like to mix many sampler2Ds into one shader, without "if" conditions, using variable m1,m2,m3 equals to 0 / 1 for each sampler2D to say if it is active or not, and multiply by 1 the sampler2Ds active at one time.

I naively wrote this function to merge 15 sampler2D's:

    //float4 blend function is a sampler2D function that "return tex2D (tex,uv);" at 3 different altitudes

    color = blend (_TexTop *m1 + _TexTop2 *m2 + _TexTop3 *m3 + _TexTop4 *m4 + _TexTop5 *m5  ,
    _TexMid *m1 + _TexMid2 *m2 + _TexMid3 *m3 + _TexMid4 *m4 + _TexMid5 *m5 ,
    _TexBot *m1 + _TexBot2 *m2 + _TexBot3 *m3 + _TexBot4 *m4 + _TexBot5 *m5 ,
    _StrataBlendWidth,  _strataAltitudeOffset,  _StrataMidbandWidth, IN.worldPos.y, IN.uv_TexTop);

Except obviously that doesnt work because it's not possible to add and multiply sampler2Ds. rarrgh!

What is the best way to rewrite the above line, to switch sampler2Ds on and off, using a 0-1 integer, without if conditions and dynaming branching?

Thankyou


Solution

  • Assuming that I've understood your question (I'm not sure), there's no way to selectively sample a texture based on a uniform paramater(mx) without branching.

    Consider a couple of facts:

    1. Branching on uniforms could not be always that expensive, since the value will be constant within the same drawcall (I guess it depends on the shader profile and the hardware, even if avoiding branches is a good rule of thumb).
    2. If in the worst case you want to use all your sample (15 seems a quite big number though), then you might consider to always sample all of them.

    I'm not sure on what's the practical use case for such a shader, btw a different approach could be compile different shader variants depending on the number of active samplers.

    For example to compile 2 variants of a shader 1 with one sampler the other with 2 you could something like:

    #pragma multi_compile ONE_SAMP TWO_SAMPLE
    
    #ifdef ONE_SAMP
    uniform sampler2D tex1;
    #endif
    #ifdef TWO_SAMP
    uniform sampler2D tex1;
    uniform sampler2D tex2;
    #endif
    
    ...
    
    #ifdef ONE_SAMP
    fixed4 col1 = tex2D(tex1,uv);
    #endif
    #ifdef TWO_SAMP
    fixed4 col1 = tex2D(tex1,uv);
    fixed4 col2 = tex2D(tex2,uv);
    #endif
    

    Then set the active keyword by script or using a custom material editor.


    EDIT

    In my answer I've assumed that m1,m2 values are uniforms, otherwise if they are not there's really no way of dynamic sampling a texture without branching.