Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Ran out of texture samplers, how to get more?

Discussion in 'Shaders' started by mcbauer, Dec 8, 2016.

  1. mcbauer

    mcbauer

    Joined:
    Oct 10, 2015
    Posts:
    495
    So I've hit the sampler limit once again with my shader. I'm at 4.0, and I'd love to say I only need like 1 or 2 more samplers but that would be a lie.

    If I start to break my shader into passes would that allow me to get in more samplers?
     
    Last edited: Dec 9, 2016
  2. kuubaas

    kuubaas

    Joined:
    Feb 26, 2014
    Posts:
    11
    Separate passes count their own samplers, yes. However, the correct solution would be atlasing. There might be tools in your asset authoring software for that but it's actually not that hard to pull off manually in some cases.

    For example I was generating several 3D LUT textures from 2D images anyway so instead pulling them into one 3D texture and nudging the shader UV coordinates was trivial and needed little extra code.

    EDIT: Yet another method would be to strip your shader down into several mutually exclusive use cases and exclude sampler declarations and their uses with shader_feature directives. This way the unused samplers will get clipped in the preprocessor and gpu will not even get to see them.
     
    Last edited: Dec 9, 2016
    mcbauer likes this.
  3. mcbauer

    mcbauer

    Joined:
    Oct 10, 2015
    Posts:
    495
    Thanks. I need to do some research into proper ways to break my shader into passes now. I am doing a blend of several textures ATM, for example, I hit my sampler limit when I tried to add a sampler that would control the smoothness. Would I now break that into a new pass?

    Atlasing is something I want to head towards eventually (no clue where to even start), and I do agree that I should break my shader into some use cases--that is a good call. However, I was going to just make separate shader files. I'm not sure about the "shader_feature directives". Something else to research.
     
  4. kuubaas

    kuubaas

    Joined:
    Feb 26, 2014
    Posts:
    11
    Several separate shaders is the good ol' way to do it with no manual preprocessing headaches. That's how Unity has done it up until before the PBR Standard shader and it still is a valid way to go. Unified megashaders do need a lot of extra engineering and upfront considerations whereas cutting your work up into multiple small shaders is the easier and by no means a less potent or less performant choice.

    As to splitting up a shader into multiple passes, you have to consider that a pass is effectively a separate layer drawn on top of the previous one. That means it has access to all the same properties and no extra information can be passed from one to another unless you do an expensive screengrab (which only gives you color information anyway). So the extra pass has to produce information from shader properties that can be mixed in additively or alpha-blended (see blend operations for full list). Specular/reflections and object outlines are good candidates for deferring to a second pass and adding to the image afterwards.

    If you really have loads of information you need to calculate and reuse, consider creating a second camera and rendering that into a screen-size RenderTexture with shader replacement (or go further with multiple render targets on one camera). Lots of reading to do but this really is a powerful technique if you want to lift more weight than your vanilla RGBA+depth can manage.

    EDIT: Also, channelwise packing is a good idea if you haven't done so. You can merge four BW textures into one RGBA file and free up three samplers. :)
     
    Last edited: Dec 9, 2016
    sanmn19 likes this.
  5. mcbauer

    mcbauer

    Joined:
    Oct 10, 2015
    Posts:
    495
    Yes, I was thinking about this earlier, and I will be going this route for sure.

    So in regards to passes, right now I think what makes the most sense with my current shader is to have all of my base color blending down in one pass, and then a second pass "on top" for the snow. I think this is where I'm having the biggest headache right now anyway--dealing with the specular difference between the 2.
     
  6. mcbauer

    mcbauer

    Joined:
    Oct 10, 2015
    Posts:
    495
    Where would one find guidance on such trivial matters? :)
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,209
    Well, you could use a 3D texture, but a texture array might be preferable.
    https://docs.unity3d.com/Manual/SL-TextureArrays.html

    If you're using target 4.0 you could also use the UNITY_DECLARE_TEX2D_NOSAMPLER macros.

    Basic setup, instead of using:
    sampler2D _myTextureA;
    sampler2D _myTextureB;


    use:
    UNITY_DECLARE_TEX2D(_myTextureA);
    UNITY_DECLARE_TEX2D_NOSAMPLER(_myTextureB);


    and instead of using:
    fixed4 texA = tex2D(_myTextureA, i.uv);
    fixed4 texB = tex2D(_myTextureB, i.uv);


    use:
    fixed4 texA = UNITY_SAMPLE_TEX2D(_myTextureA, i.uv);
    fixed4 texB = UNITY_SAMPLE_TEX2D_SAMPLER(_myTextureB, _myTextureA, i.uv);

    This separates the sampler (the thing that reads a texture) and the texture apart and lets you reuse the sampler from one texture for many. This also means any settings you have for the first texture will get reused for the rest (i.e.: if your _myTextureA is point sampled, they all will be).
     
  8. mcbauer

    mcbauer

    Joined:
    Oct 10, 2015
    Posts:
    495
    very cool, thanks bgolus!