Search Unity

Feature Request Editor-specific shader workflow

Discussion in 'Shaders' started by hippocoder, Aug 1, 2021.

  1. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Hi, please add one for Unity Editor as well so that the shader for editor side can be different to the deployed shader. This allows for major optimisations, cleaner sources and so debug visuals, solving very similar problems this feature does, and increases value of this feature.
     
    april_4_short and LaireonGames like this.
  2. april_4_short

    april_4_short

    Joined:
    Jul 19, 2021
    Posts:
    489
    Proxy shaders!

    Yes, PLEASE!!!
     
  3. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    @hippocoder would a "UNITY_EDITOR" macro be enough?
     
    LaireonGames and hippocoder like this.
  4. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    Or would you like to have editor-only passes and subshaders?
     
  5. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Hmmm if we can have editor only passes and subshaders as well, it would extend the usefulness. I would like to hear what @bgolus thinks too, as they'd seemed interested in this as well.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    The old thought was just to have a keyword, though more recently I've realized ideally it would be one that could be disabled while in the editor for testing. I've mentioned elsewhere that I've work around this before with
    #if UNITY_EDITOR
    c# scripts that set a global keyword, but the side effect of this is obviously those variants can end up in the build. This isn't really the end of the world, but depending on the shader could mean several megs of "useless" data, so I usually try to comment out the
    #pragam multi_compile
    lines for it once we get close to final release. Or I've abused platform defines when working on projects that won't be shipping on PC to detect when "in the editor".

    Thinking about it more right now, I actually wonder if something like a built in
    #pragma multi_compile_editor
    that the build and shader variant collection would ignore couldn't be useful, and/or maybe something akin to the project settings' Scripting Define Symbols, but for shaders to let use set our own global platform keywords.
     
  7. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    3,136
  8. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    I see.

    The easiest thing to add would be a
    #pragma editor_only
    command to exclude a pass from the build.
    Everything else is... more involved :)

    Let me expand on each of the options a bit.

    #pragma multi_compile_editor (along with all shader_feature variations as well): There are some interesting edge-cases. The same keyword can be present in two different directives, one for Editor only and one for both Editor and player. We'd need to account for that, and make some rules to resolve this. Also, it would probably be nice if those keywords didn't end up in the player build at all (as part of the keyword space for a given shader). Still, this one is less work than the other options.

    UNITY_EDITOR macro: right now the Editor maintains import-time data for the active build target only. Import data contains keyword-defining directives. If these start to differ between the Editor and the player, we'll have to account for this in quite some places :) Also, this doubles at least some part of the import time for all shaders, unless we add code to figure out, whether the given pass actually depends on the UNITY_EDITOR macro or not.

    Set custom platform keywords: this one is really thorny. We thought about adding this, but this brings a reimport of all shaders when modifying this set. This can be reduced to "reimport all shaders when a keyword got added; reimport those that we know depend on a given keyword when it's removed or changed", which also requires tracking per shader, which platform keywords have an effect on it, which, in turn, makes preprocessing a little slower.
     
    JoNax97 and hippocoder like this.
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    This is a usable option for the BIRP. It's slightly less convenient for some use cases (ie: wanting to show data validation feedback ala the Material Validation Scene view modes), but workable. My issue with this option is it doesn't really work for the SRPs since they have intentionally limited multi-pass shader support. If I was going to separate out stuff to a separate pass, I'd just make it a separate shader & material and attach it to an editor only object / script to make sure it doesn't get caught by the build's resource tracking. In the past were I've done this kind of thing I usually generate the material in code and use a
    #if UNITY_EDITOR
    covered
    Shader.Find()
    , and manually pull it from any Shader Variant Collection once we start using one. That last step is the only thing it potentially helps with, which might in itself be enough to make it worthwhile to add for some personal sanity depending on the current project / team workflow and how / how often the variant collection is being updated.

    Doesn't this edge case already kind of exist if you have the same keyword in a multi_compile and shader_feature? Shaders already throw warnings on duplicate keywords. To me this is the same issue, though maybe it should be an error instead of a warning.

    Though I should note when I originally wrote
    multi_compile_editor
    I was thinking of it explicitly like a
    multi_compile_instancing
    or other built in multi_compile where the keywords aren't user assignable, but more literally a
    #pragma multi_compile _ UNITY_EDITOR
    equivalent. For editor only shaders I'll make heavy use of dynamic branching rather than keyword variants as I'm not concerned that the current GPU can't do that efficiently. And in the few cases I've wanted to be able to control per-renderer settings for debug visualization I tend to lean heavily on using MaterialPropertyBlocks instead of instanced materials, so I explicitly can't make use of per-material keywords. Though I've also not moved to using SRPs for any of our projects where property blocks are decidedly less useful due to not having SRP Batcher support... which is another topic for a different thread.

    That was kind of the idea behind having the fixed keyword version of
    #pragma multi_compile_editor
    . Let it get dirty in the editor and make a lot more variants. But just make sure things like the build pipeline and shader variant collection system explicitly avoid adding the
    UNITY_EDITOR
    keyword variants. The alternative with people adding their own "editor only" keywords via
    shader_feature
    or
    multi_compile
    already comes with the pain of increased import times ... because more variants inherently make that more expensive.

    Since that's already what happens to c# when you use Scripting Define Symbols, this seems like a worthwhile trade. Though presumably something like the user assignable
    #pragma multi_compile_editor MY_EDITOR_KEYWORD
    could be used to limit reimporting to just those shaders, I get that it'd have to be tracked and make everything slightly slower. But it's more an "interesting concept" than one I'm especially stuck on.


    To me (without direct insight into the internal code) having a single
    UNITY_EDITOR
    keyword that is excluded from builds and has to be explicitly added to a pass via a
    #pragma multi_compile_editor
    feels like the most straightforward and least painful way to implement this. It also allows an easy path for allowing it to be toggled in the scene view effects toggles / game view gizmos / editor wide setting.
     
  10. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    This is correct for surface shaders only. For other shaders it would just have to parse some extra characters.

    I was not talking about a keyword :)
    It could be a macro that is always defined for shaders imported and compiled for the Editor use, independent of build target or anything. This means you could do things like
    Code (CSharp):
    1. #if !UNITY_EDITOR
    2. #pragma multi_compile A B
    3. ...
    4. #else
    5. ...
    6. #endif
     
    bgolus likes this.
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    I would say that's probably how most people would expect it to work, as that's how it works in c#. Though I'm also heavily in favor of shader stuff that can be easily toggled off in the editor for easier testing and iteration. Granted comment out a few lines isn't too hard. I'd also want the "compile and show code" to either have the option to toggle or never have
    UNITY_EDITOR
    enabled.
     
  12. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    We had a conversation about this internally. It seems that most of that can be really solved with a
    UNITY_EDITOR
    define for the shaders in the Editor.
    The macro will not ever be defined in the player, it will not affect variants that go there. You can add conditionals based on it around pragmas.
    "Compile and show code" - sure, a checkbox should do the trick. One may want to check, what the Editor uses.

    As for custom platform keywords - one could make a ".hlsl" file and put any defines one needs in it. It's less convenient as is has to be included it in each shader and won't have a builtin C# API, but serves as a workaround for now :)
     
    bgolus likes this.