Search Unity

Feedback Graphics.DrawRenderer function to resubmit the renderer with a different material

Discussion in 'General Graphics' started by Prodigga, Feb 28, 2019.

  1. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Hello there!

    Requested functionality:


    We should be able to 'submit' a copy of a Renderer for drawing but with the ability to override some properties - most importantly the material, but maybe the TRS matrix and layer mask as well. It should also have an option to use the target renderers MaterialPropertyBlock for the render operation. The requested feature would be functionality equivalent to adding multiple materials to the renderers sharedMaterial list, without actually touch the list.

    Code (CSharp):
    1. public static void Graphics.DrawRenderer(Renderer renderer, Matrix4x4 matrix, Material material, int layer, Camera camera = null, int submeshIndex = 0, bool useRenderersMaterialProperties = true, bool castShadows = true, bool receiveShadows = true, bool useLightProbes = true)

    Existing Solutions and their problems:

    Use MultiPass shaders

    The LWRP does not support multi pass shaders. On top of this, there is something nice about braking complex shaders into their smaller components and allowing our artsist to mix and match at edit time. For example, we can have an 'Outline' effect which gives an object an outline, and the artist could use that material in conjunction with whatever material they wanted to use to render a given object by adding both materials to the Renderer's material list.​

    Use Graphics.DrawMesh

    We have Graphics.DrawMesh, which takes a mesh and those other properties and submits it to be rendered. This is almost perfect! However, it doesn't work with SkinnedMeshRenderers, and baking a SkinnedMeshRender mesh every frame is immensely inefficient and it doesn't work with ParticleSystemRenders' either.
    Assign multiple materials to Renderer

    This is what we currently do, however this gets very messy if these materials are 'procedurally generated' and it is especially messy if you want to be able to preview your effect outside of play mode as well.

    We have some effects that require us to render a renderer multiple times with different materials on top of the one that our artist has assigned to the renderer. This has a lot of issues:
    • We need to micro manage the 'sharedMaterials' list of the Renderer during runtime and edit time too. We have to deal with a lot of editor quirks because we are adding materials to the sharedMaterials list which dirties the field (and in the case of prefabs, causes the field to become 'overridden'), and since the materials are procedurally generated we have to make sure we clean up after ourselves otherwise the materials get deleted and the prefabs/scene objects get saved with missing materials in their sharedMaterials array.
    • Its hard for multiple different effects to co-exists, since there is only one sharedMaterials list that both effects would like to write in to. For example, we might have 2 scripts, where one attaches a custom 'ShadowPass' material and another attaches a 'OutlinePass' material. The scripts need to preserve the artists 'initial list' of materials, and make sure they dont touch each others materials. It is a hot mess. We've written a 'RendererMaterialManager' script to facilitate the interaction different effects.
    How the proposed feature fixes the issue:

    The artists regains complete control over the renderers material list. Whatever they put in there is what is used to render the renderer.

    No need to micro manage the list of sharedMaterials. Custom effect behaviours can manage their own materials that they care about and submit Render calls to render that renderer again with their materials.

    Our effect behaviour scripts become a lot simpler. The scripts can simple be marked as ExecuteAlways, and in their Update method they can call Graphics.DrawRenderer(myRenderer, myCustomMaterial, ... ); and it would work both during 'edit time' and 'runtime', with no need to manage the material list on the renderer. It becomes 'plug and play'. No issues with 'prefabs saving' with dirty sharedMaterails list, etc.

    No 'coexist' issues between effect scripts. Effect scripts handle their own materials and submit their own render calls. They don't need to worry about another script deleting or reseting their materials like they would if they had to add it to the renderers sharedMaterial list.
     
    JoHSol and Peter77 like this.
  2. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Bump...
     
  3. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Hi its me with another bump
     
  4. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Bump.

    The LWRP 'RenderObjects' ScriptableRendererFeature is *almost* good enough.. The 2 issues with it are:
    • The rendered objects must be entirely before or entirely after the other objects being rendered.
      • Adding a second material to the Materials list on a renderer re-renders that object and sorts it correctly based on the materials render queue. This does not seem possible with 'RenderObjects' - if I want a renderer to render twice I need to do it entirely before or entirely after everything else.
    • Objects can only be filtered using the Layermask, and that is very limiting.
      • This is easily fixable by allowing us to filter objects using the Renderering Layer Mask. Is this planned? Seems like an oversight that we cannot do this.
    Tagging @phil_lira because I don't think this will get any attention any other way.
     
    Kronnect likes this.