Search Unity

Question SpriteRenderer + shader properties override breakes SRP Batch

Discussion in 'Universal Render Pipeline' started by Tony_Max, Nov 16, 2021.

  1. Tony_Max

    Tony_Max

    Joined:
    Feb 7, 2017
    Posts:
    353
    Problem: I use a bunch of sprites with same material and same textures (generated by sprite atlas) + shader graph sprite lit shader. In c# script i modify shader property and this breaks SRP batching.

    What i want to achieve: I want to recolor my pixel art on fly, so i use a little trick: mapped texture + palette texture = recolored art. Palette texture is Nx1 size texture with sequence of unique pixels and mapped texture is a texture (which colors we want to restore from palette texture) each pixel of which contains value of where on palette texure we need to sample pixel. So in test project i have same atlas for everything. My shader have only 3 properties: _MainTex, _PaletteTex, _PaletteUV (float4). And all my sprites in scene has the same _MainTex and _PaletteTex (which is the same texture also because i'm using just one atlas for testing). So i see in Frame debugger that the only difference is _PaletteUV value, and this difference breakes SRP batching.

    Why this confusing me?: there is label "SRP batching: compatible" in my sprite lit shader, but there is some information on forum that rendering sprites is a bit "special" thing and it breakes batching here and there. Also there is a reply from @bgolus

    Question: What can i do with that? Have you any idea / same cases? I can any time generate tones of sprite variants and pack them into sprite atlas and render with sprite default material, but using shader is much much cleaner. Also i can try to use Graphics.DrawMeshInstanced, but i'll lose all this SortingGroup and other stuff.
     
    Last edited: Nov 16, 2021
  2. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,514
    To avoid breaking batching, you could send over your palette coordinate in a different way for instance through the vertex color. Note, SpriteRenderer.color says it is a Color but its really is Color32. There's also position.z if you're not otherwise using that value.

    By using SpriteRenderer.color, you need to use a non-ShaderGraph shader because Sprite Lit and Unlit auto-apply that color with a simple multiply in such a way you don't have an option to disable it within Shader Graph.
     
  3. Tony_Max

    Tony_Max

    Joined:
    Feb 7, 2017
    Posts:
    353
    I've ended up with writing my own sprite render system and 1 evening spent i've got my sprites rendered through Graphics.DrawMeshInstanced with different main and palette textures all in the same atlas and just for 1 instanced draw call.
     
  4. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,514
    How'd you end up handling the sorting groups?
     
  5. Tony_Max

    Tony_Max

    Joined:
    Feb 7, 2017
    Posts:
    353
    I'm not quite yet there, for now i'm trying to understand how DrawMeshInstancedInderect works. I want to find clever solution about sorting group to be able to calculate sorting group + sorting order to global sorting order and then use DrawMeshInstancedInderect in the most optimal way.
     
  6. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,514
    Did you have success?
     
  7. Tony_Max

    Tony_Max

    Joined:
    Feb 7, 2017
    Posts:
    353
    Not yet, but i move straight :) Yesterday i've came up with fact that i can't use ShaderGraph + ComputeBuffers, because second requires StructuredBuffer in shader and ShaderGraph has only OverridePropertyDeclaration -> HybridInstanced wich makes it compatible with DOTS MeshRendererV2 system and not actually generate any of StructuredBuffer (but MaterialPropertyBlock.Set[Type]Array works with HybridInstanced, and i can't figure out why). So for today i've planned to dive into writing URP compatible shaders from scratch.
     
  8. Seromu

    Seromu

    Joined:
    Nov 30, 2015
    Posts:
    34