Search Unity

Material Property Block

Discussion in 'Shaders' started by taloskal, Aug 10, 2020.

  1. taloskal

    taloskal

    Joined:
    May 2, 2020
    Posts:
    10
    Hello there, new to Unity. I am working on a project that heavily depends on GPU instancing, however I need to set a material property block for color, albedo, normal and occlusion masks, as well as tiling. This is such that I can batch objects that use the same material with variants of these 5 properties. Does anyone know any free resource that meets these requirements? Material property blocks seem very important yet the free resources I've been able to find are basic and sparse. I am also very new to shaders so I haven't been able to do much myself...

    Many thanks in advance.
     
    Last edited: Aug 10, 2020
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Because what you want to do is somewhere between impossible and very advanced.

    GPU instancing only allows you to modify numerical values between instances. Textures are not numerical values, and thus two meshes cannot be instanced if they use different textures. So if you use the material property block to set different textures, it'll be breaking instancing and be no better (or potentially worse) than if it wasn't instanced at all.

    GPU instancing works by taking all of the numerical values and putting them into arrays. The CPU then tells the GPU "render x number of this mesh". The shader then gets told which number of the instance it is, and that value can be used to get the correct value from the array. GPUs do not support arrays of textures*, hence why you can't have instanced meshes with different textures.

    The answer is "use a
    Texture2DArray
    ". Which sounds like I'm saying "do the thing I just said GPUs can't do". But a
    Texture2DArray
    is a texture type that the GPU considers to be a "single texture", it just happens to have several layers. It's basically a
    Texture3D
    that doesn't do any filtering between the third axis. So you have to manually generate a
    Texture2DArray
    , assign that to your material, and have a custom shader that has a "texture index" instanced property that it uses to get the correct texture.

    * Vulkan and DX12 let you put a bunch of textures in a big lump and grab them from a dynamic index, but I don't think you can do that in Unity yet.
     
    EgoJacky likes this.
  3. taloskal

    taloskal

    Joined:
    May 2, 2020
    Posts:
    10
    Firstly thank you for your useful insights, I was not aware of this being advanced to nearly impossible, so it is great to have my expectations lowered. I guess I can do fine with just having control over the color and tiling, no need to have material property blocks for the rest... But out of interest, I see you mentioning Texture2DArray. Is there any difference between a texture atlas and Texture2DArray? Usually, the main limitation for me regarding texture atlases is tiling, which is essential for my project. Is it possible to tile textures within a Texture2DArray individually? (i.e. one texture using a tiling of (2,2) while the other uses a tiling of (1,1)).
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    That's the main advantage
    Texture2DArray
    s have over using an atlas, tiling. Each layer within the texture acts just like a normal
    Texture2D
    . It also means you don't have to worry about padding like you do with an atlas to prevent color bleeds from tight UVs and/or mip map levels.

    The one caveat to
    Texture2DArray
    is every layer in a specific array needs to be the same size & format.

    Also know if you do want to have separate tiling & offset values per mesh, you can't use the built in tiling & offset properties. Those are never instanced. You must use a custom
    Vector
    /
    float4
    property.
     
  5. taloskal

    taloskal

    Joined:
    May 2, 2020
    Posts:
    10
    I see, interesting. Looks like a challenge worth the try, I'll see what I can do. Thank you for your insights, Texture2DArray looks promising and using a vector / float4 for tilling will be essential for what I plan on doing.
     
  6. taloskal

    taloskal

    Joined:
    May 2, 2020
    Posts:
    10
    I hear that when using the Universal Render Pipeline, materials with similar properties from the same shader can be batched together using the SRP Batcher. Is there any advantage to using material property blocks instead of relying on the SRP Batcher?
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    SRP Batcher is not instancing. They have different pros and cons.

    Not knowing what your use case is, I can't answer that question. Even knowing it I probably can't answer it honestly, as it'll be highly dependent on your scene setup and target platform. I broke down the difference between the various ways to render stuff in Unity here:
    https://forum.unity.com/threads/srp-batcher-and-gpu-instancing.833362/#post-5521216
     
  8. taloskal

    taloskal

    Joined:
    May 2, 2020
    Posts:
    10
    My usecase is effectively rendering rigidbody cubes with different tilings and colors. Since the limits of the SRP batcher are unknown to me, I did some tests and it looks like it can batch together up to 300 of these cubes, which seems promising. However in my current test I only used two variants of the same shader, but I can see that it can batch together meshes that use either of the two. I shall now test it with more shader variants and see if it remains the same. Changing shader properties such as tiling at run-time will also be needed, so I shall test that as well.