Search Unity

MaterialPropertyBlock.SetTexture breaks batching

Discussion in 'Shaders' started by tomkail2, Aug 31, 2021.

  1. tomkail2

    tomkail2

    Joined:
    Jul 22, 2011
    Posts:
    25
    Hello! We've run into a slightly strange issue with batching and property blocks.

    Our hope was that we could batch all objects sharing the same texture, using property blocks to change, say, color.

    This seems to work a treat when using a material with a fixed texture, dragged into the material from the inspector - but we've found that when we use MaterialPropertyBlock.SetTexture, objects with different colors stop batching.

    We'd have assumed that this is just a limitation of MaterialPropertyBlock.SetTexture - we'd read that it always breaks batching, fair enough - but we've found that so long as the objects have the same color then they ARE batched, even when SetTexture is used.
    So there's some awareness that SetTexture doesn't NEED to break batching, but it seems like batching fails when both the texture and color are different.

    We can't find any information on why this is the case. Can anyone shed any light on this?

    As you'd expect, creating a new material for each texture and then controlling the colors via MaterialPropertyBlock allow them to batch. We'd rather avoid having to create materials for each texture though - but perhaps this is simply what we need to do?
     
  2. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,756
    I'm confused, you're saying that you have materials with the same color but different textures and somehow those meshes batch together?
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    SetTexture absolutely breaks batching ... specifically it won't batch together objects using different textures. There's no getting around that. It's a GPU & Graphics API limitation that can't be worked around.

    However setting multiple objects to use the same texture can still let them get batched together. Unity's Sprite and UI systems makes extensive use of this and wouldn't work very well if that wasn't the case. It will also batch any objects with the exact same color together too. But it has to be exactly the same color. Any minor floating point differences and it won't batch them.
     
  4. tomkail2

    tomkail2

    Joined:
    Jul 22, 2011
    Posts:
    25
    Thanks for this! What we've found strange is that without using SetTexture, objects with different colors batch, but when using SetTexture (using the same texture), objects must be of the same color to batch. If this is the sort of thing you mean by can then fair enough! I'd be very curious to understand why this is the case though.

    We've been wondering about solutions. The best we've got is to try making a new instance of the material for each texture so we can remove SetTexture and take advantage of batching when colors change. If we then use texture atlasing we hope to be able to batch a LOT of things at once. In some very light tests it seems to work, although we're feeling in the dark a little!
     
  5. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,756
    Unless you are using something that sets the color to the vertices and the shader uses vertex color, objects with different colors will not batch.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    You absolutely can't batch objects with different colors together. They can GPU instance though. It's confusing because the game view stats will show dynamic & static batching, and instancing under the "batches" number. But if you use the frame debugger they'll be shown as a draw mesh (instanced).
     
  7. tomkail2

    tomkail2

    Joined:
    Jul 22, 2011
    Posts:
    25
    Oh! Thank you, that's really useful. You're quite right - I've been saying "batching" when I mean "reducing draw calls". The game view stats is rather misleading! I suppose it really means "number of draw calls saved"?
    Anyway - the same question applies - assuming SetTexture prevents instancing, as well as batching (as seems to be the case), I'd like to understand if we can/should reduce draw calls by creating a new material for each texture and then changing the colors via property blocks.

    Thanks again, I really appreciate it! This stuff can be really tricky to learn.
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    There's functionally no difference, at least in terms of batching / instancing behavior, between using material property blocks or separate materials to change the texture. Both will stop batching or instancing between objects that use different textures. It can be confusing as to when Unity decides to dynamic batch vs gpu instance.

    Unity's default instancing behavior will also only try to "batch" together objects that appear successively after being depth sorted. The only 100% sure way to get all objects that can be rendered as a single instance to be drawn in a single draw call is to manually render them using
    Graphics.DrawMeshInstanced
    or command buffers instead of relying on Unity's built in "batching" systems.

    I wrote a longish post about the different types of batching Unity has here:
    https://forum.unity.com/threads/srp-batcher-and-gpu-instancing.833362/#post-5521216
     
    tomkail2 likes this.