Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Using MaterialPropertyBlocks with ShaderGraph shaders (help wanted)

Discussion in 'Shaders' started by Rienhl, Mar 27, 2019.

  1. Rienhl

    Rienhl

    Joined:
    Nov 14, 2013
    Posts:
    41
    Hello!

    I'm trying to use material instancing with a shader created with ShaderGraph. I don't seem to find the way to set any property to be used in a MaterialPropertyBlock.

    I tried compiling the shader's code, adding the [PerRenderData] attribute before the property declaration but t doesn't work. Also, it looks like it can't be saved at all since when I open the code again, my [PerRenderData] attribute gets deleted.

    How should I approach this?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    6,973
    This doesn’t do anything. It’s singular purpose is to hide the value in the inspector. It’s a legacy setting related to the Sprite Renderer and even there is unnecessary. There’s nothing you need to do to make material properties work with material property blocks, they all work by default.

    The one thing with Shader Graph is the name of the material property variable isn’t obvious as the name you set is just the display name, the actual variable gets an auto generated random string like _Vector_H264BBQUSB. Expand the property in the blackboard and change the reference name from the aforementioned gobblygook to something sensible, like _MyVector.
     
  3. Rienhl

    Rienhl

    Joined:
    Nov 14, 2013
    Posts:
    41
    Thanks for the answer man.

    So, in this post the author says
    . If this is the case then I don't see the point of using the MaterialPropertybLock here since I'm going for the GPU Instancing stuff.

    Also, in this other post the author says
    I'm confused about what can actually be done and how. I can't find any consistent documentation. Have I skipped a section of the Unity Manual?

    When wanting to replace textures while using GPU instancing, what's your recommended way?
    Should I use a Texture asset or a RenderTexture on the MaterialPropertyBlock?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    6,973
    Yep, I'm familiar with that post. It is wrong.

    To the best of my knowledge it was wrong when the author originally posted it too. If you follow the steps he describes and simply omitting the [PerRenderData] step, it produces the exact same result. I can only guess the author never actually tested with out using [PerRenderData], or when they did had some bug in their code. It's unfortunate because so much of the information is useful, and it comes up often. It also predates Unity's GPU instancing support by about 3 months! It's often sited by people when taking about instancing, but it isn't what that post is doing!

    This post is correct. You cannot change the texture and still instance. Well, to be more precise, two objects with different textures cannot be instanced together. This is a GPU & graphics API limitation, not something Unity is imposing themselves.

    The way instancing works is each instance of a mesh gets rendered by the GPU with a different instance id that's passed to the shader. Every single instance is in fact using the exact same "material" with the exact same settings. The bit of magic is instanced properties are put into an array of values that's set on the material rather than a singular value. So when an instance is rendered, and your shader has the _Color value setup as an instanced property, then instead of doing:
    fixed4 col = _Color;

    it's doing
    fixed4 col = _Color[instanceID];

    The problem is you can't have dynamic arrays of textures. It's simply not supported by any graphics API. You can only have arrays of floats, ints, or bools.

    But that's why the Texture2DArray exists. It's a type of texture that is itself an array with multiple slices. Unity supports these, but offers no in editor tools for creating or managing them. So you have to do that yourself with custom scripts. Then you set the single Texture2DArray texture object on your material, and for each renderer you can set which index to use when reading from the array texture.


    But, there's one really big problem...
    Unity doesn't yet appear to support defining instanced properties in Shader Graph!!! The ShaderGraph materials themselves do support instancing, and multiple objects using the same material and mesh will be instanced, there's no way to set properties to be instanced properties, so this is all kind of moot. There's still good reasons to use material property blocks over setting values on a material directly, but not related for allowing instancing. :(
     
  5. Rienhl

    Rienhl

    Joined:
    Nov 14, 2013
    Posts:
    41
    Wow, you really went over the top with this answer! I appreciate it a lot!
    Thank you so much!
     
    amisner2k likes this.
  6. amisner2k

    amisner2k

    Joined:
    Jan 9, 2017
    Posts:
    28
    That racing snail really knows his stuff. :D
     
  7. Gekigengar

    Gekigengar

    Joined:
    Jan 20, 2013
    Posts:
    406
    Is this supported by Shader Graph yet?