Search Unity

MaterialPropertyBlock Increases Draw Call?

Discussion in 'Shaders' started by Mikeysee, Oct 31, 2014.

  1. Mikeysee

    Mikeysee

    Joined:
    Oct 14, 2013
    Posts:
    155
    Hey,

    Apologies if this isn't strictly shader related but I assume you guys will have had to deal with this alot and thus may be able to answer it for me..

    Im not sure if im using the MaterialPropertyBlock property correctly as it seems that if I set MaterialPropertyBlock different for one object than another then it acts like I set a different material and increases the draw calls.

    Im using it like the following:

    Code (CSharp):
    1.     public class SpriteEffects : MonoBehaviour
    2.     {
    3.         [Range(0, 1)]
    4.         public float greyscaleAmount = 0;
    5.  
    6.         [Range(0, 2)]
    7.         public float brightnessAmount = 1;
    8.      
    9.         private float lastGreyscaleAmount = -1;
    10.         private float lastBrightnessAmount = -1;      
    11.  
    12.         private MaterialPropertyBlock props;
    13.  
    14.         void Start()
    15.         {
    16.             props = new MaterialPropertyBlock();
    17.         }
    18.  
    19.         void Update()
    20.         {
    21.             if (greyscaleAmount == lastGreyscaleAmount && lastBrightnessAmount == brightnessAmount)
    22.                 return;
    23.  
    24.             lastGreyscaleAmount = greyscaleAmount;
    25.             lastBrightnessAmount = brightnessAmount;
    26.  
    27.             renderer.GetPropertyBlock(props);
    28.             props.AddFloat("_GreyscaleAmount", greyscaleAmount);
    29.             props.AddFloat("_BrightnessAmount", brightnessAmount);
    30.             renderer.SetPropertyBlock(props);
    31.         }
    32.     }
    Anyone any clues?
     
    Last edited: Oct 31, 2014
  2. Mikeysee

    Mikeysee

    Joined:
    Oct 14, 2013
    Posts:
    155
    I tried spying at the SpriteRenderer to see how Unity does it but unfortunately its all internal calls :(

    Code (CSharp):
    1.     public sealed class SpriteRenderer : Renderer
    2.     {
    3.         public Sprite sprite
    4.         {
    5.             get
    6.             {
    7.                 return this.GetSprite_INTERNAL();
    8.             }
    9.             set
    10.             {
    11.                 this.SetSprite_INTERNAL(value);
    12.             }
    13.         }
    14.         public Color color
    15.         {
    16.             get
    17.             {
    18.                 Color result;
    19.                 this.INTERNAL_get_color(out result);
    20.                 return result;
    21.             }
    22.             set
    23.             {
    24.                 this.INTERNAL_set_color(ref value);
    25.             }
    26.         }
    27.         [WrapperlessIcall]
    28.         [MethodImpl(MethodImplOptions.InternalCall)]
    29.         private extern Sprite GetSprite_INTERNAL();
    30.         [WrapperlessIcall]
    31.         [MethodImpl(MethodImplOptions.InternalCall)]
    32.         private extern void SetSprite_INTERNAL(Sprite sprite);
    33.         [WrapperlessIcall]
    34.         [MethodImpl(MethodImplOptions.InternalCall)]
    35.         private extern void INTERNAL_get_color(out Color value);
    36.         [WrapperlessIcall]
    37.         [MethodImpl(MethodImplOptions.InternalCall)]
    38.         private extern void INTERNAL_set_color(ref Color value);
    39.     }
     
  3. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    When material properties or materials are different between two objects then two objects can't batched together (with dynamic batch or static batch). Also it results in a Material.SetPass call.
     
  4. Mikeysee

    Mikeysee

    Joined:
    Oct 14, 2013
    Posts:
    155
    How does the SpriteRenderer do it then? I believe it uses a [PerRendererData] for the _mainTex in the shader and thus you can have thousands of sprites on screen and the draw call count will be one (if they all share the same atlas)..

    EDIT: Unless it encodes the sprite offset within the atlas in the vertex data and thus the Matarial's properties stay the same, its just the vertex data that changes..

    In that case is there any way to get at the vertex buffer for the SpriteRenderer? Why is that class sealed?

    BTW I appreciate the reply Joachim
     
    Last edited: Nov 2, 2014
  5. sunmachine

    sunmachine

    Joined:
    Jun 4, 2014
    Posts:
    9
    Heyo, just looking into draw calls and material property blocks myself. I think I have a reasonable theory to answer this. The sprite renderer generates geometry and UVs against the image data of an atlas, and as evidenced by my work with creating custom shaders that interact with sprite renderer specifically, the colors you adjust actually are deposited as vertex color on this generated mesh.

    Because of this, the material is never actually using custom values across different sprites. Only the sprite mesh's UVs, vertex position, and vertex color change. Hence, assuming the sprite data is referencing the same sprite sheet (and therefore the same material property block value for the sprite atlas on _MainTex), draw calls will batch.

    Ballpark? Clear miss?
     
    unityBerserker and _Yash_ like this.