Search Unity

ifdef for URP?

Discussion in 'Universal Render Pipeline' started by joshcamas, Apr 3, 2020.

  1. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,278
    Is there a shader define for whether URP is enabled, as opposed to standard or HDRP?
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    Hi!
    No, there is no such define. Shader compiler has no idea (and shouldn't, really), what kind of render pipeline the shader belongs to.
    You can have custom defines in shaders themselves, if you want.
     
    joshcamas likes this.
  3. StaggartCreations

    StaggartCreations

    Joined:
    Feb 18, 2015
    Posts:
    2,266
    There are a several definitions declared throughout the shader library such UNIVERSAL_PIPELINE_CORE_INCLUDED and UNIVERSAL_LIGHTING_INCLUDED

    The core SRP library has a few as well, such as the installed version.
     
  4. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    Right, but these might change, as they are just include file guards, and also depend on order of includes.
    So I wouldn't depend on those.
     
  5. equalsequals

    equalsequals

    Joined:
    Sep 27, 2010
    Posts:
    154
    This is where you would want to use a SubShader for each supported pipeline. You could then define your own.
     
  6. TLuthDidimo

    TLuthDidimo

    Joined:
    Jul 11, 2021
    Posts:
    9
    This does make supporting multiple render pipelines a bit of a nightmare. I'd like to say to unity 'don't compile this thing and generate a bunch of errors' when the environment is using one or another render pipeline.
    In my work, I have to support versions of HDRP, URP and BIRP shaders but Unity really doesn't seem to want me to.
     
  7. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
  8. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    727
    You say they shouldn't, but here's an example.

    I have a plugin on the asset store which uses ShaderGraph, in order to easily support BiRP, URP, and HDRP. For some reason, a custom shader node works with URP but not with HDRP. How should an asset store developer be able to write a custom function node which handles this? The custom node needs some macro to depend on to know if its compiling for URP or HDRP, to use whatever code is appropriate for whatever pipeline the developer using the plugin is on.
     
    joshcamas likes this.
  9. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    This should be done by SG, it already knows which pipeline is the target.

    "Which render pipeline does this shader belong to" is definitely not a concept for the shader compiler. All it should care about is "here's HLSL code with some macros, let's preprocess and compile it". There are macros that the compiler should know about, but those are based on things like target platform or graphics API which also affect code generation by the compiler itself.
     
  10. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    727
    Well, it's not. And I wouldnt expect ShaderGraph to handle my custom nodes. Here's an example of where it fails.

    I want a ShaderGraph shader to handle procedural instancing (DrawMeshInstancedIndirect). ShaderGraph doesnt support this out of the box, so I needed to inject the necessary pragmas via a custom node.

    Unity_NDddNfgDq3.png

    This means I need a custom node for the function "foliageSetup()"

    upload_2022-11-22_8-56-14.png

    This simple function works fine on BiRP and URP, but fails to compile on HDRP. If my asset store plugin wants to seamlessly support all three, what am I supposed to do here? There's no define for me to check against to do something different for HDRP.
     
  11. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    All I'm saying is "SG should define it". I can forward this to the SG team :)
     
    funkyCoty likes this.
  12. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    727
    Yeah, I can agree with that. Thanks!
     
  13. BOXOPHOBIC

    BOXOPHOBIC

    Joined:
    Jul 17, 2015
    Posts:
    509
    I think unity just doesn't understand what an asset store developer needs and cares even less to address these issues. Let's debate this for 5 more years, or 10 to get in sync with unity's timeline. If unity is so afraid that those defines could change and break stuff or whatever the reason for not adding them, why are my shaders breaking from 12.1.6 to 12.1.7. Clearly avoiding breaking things is not one of them.

    If you need real-world examples, here is one of my assets, where I need to switch by pipeline and by urp version. Luckily, Amplify provides a Switch by Pipeline node, Switch by SRP Version node, and also defines the SRP version, to get S*** done.

    upload_2022-11-24_9-34-58.png

    In my shaders, I always have a few defines, just in case some 3rd party developer or amplify user wants to filter some things out or even filter the materials in code if needed.
    upload_2022-11-24_9-47-58.png

    So my question is, why is unity refusing to add those defines when people are asking for them since the beginning?
     

    Attached Files:

  14. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    @funkyCoty I forwarded your request :)
    @BOXOPHOBIC the only system provided by Unity right now that allows you to target different RPs simultaneously is ShaderGraph. This is the only place where such a define would make sense.
    I haven't seen a request to add this define to ShaderGraph (also, I'm not saying there wasn't one - I just don't know).
    We'll definitely have a way to add RP-specific things in Block Shaders.
     
    BOXOPHOBIC likes this.
  15. BOXOPHOBIC

    BOXOPHOBIC

    Joined:
    Jul 17, 2015
    Posts:
    509
    Exactly there. We are talking about asset store developers who target multiple pipelines. Imagine a fancy calculation for HDRP, a cheaper one for URP in the same shader. Or some math on HDRP taking camera relative rendering pos into account, but not in URP. We already have a define for this, but if URP adds it as well, maybe I want to make things different for each pipeline. Or whatever the user wants to make different for each pipeline in one shader. You get the idea.

    I saw forum posts about shaders defines and scripting defines on this topic. I think made a request for a SwitchByPipeline node for SG on the roadmap, but for some reason, I can't see my requests. Or at least I think this one was of the requests I made.
     
  16. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    @BOXOPHOBIC I fully understand the value of "tell me which pipeline I'm working with" :)
    More than that, I think it would be simple to add it to SG.
     
    BOXOPHOBIC likes this.
  17. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
  18. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    121
    The above workaround only works if the Core.hlsl is imported like from SG. From a custom shader I cannot use that to conditionally include Core.hlsl file.

    I naively thought that there could be an easy way to detect RP in code/shader/editor/build.
    Instead I ended up spending weeks to figure this out just to support Built-in and URP...

    Anyway, here is how I finally managed to make it work and if anyone has a better way I will much appreciate it because then I can delete all of this and ship less boilerplate.

    1. Making it work from code
    This script will automatically detect the pipeline and create a Scripting Define Symbol.

    https://gist.github.com/cjaube/944b0d5221808c2a761d616f29deaf49

    It also HAS to go into Assets/Editor folder, or it will not get compiled before the rest of the code that depends on that define and errors will be thrown when you try to import your code all at once like with a unitypackage.

    You can see it was added in URP under Project Settings > Player > Scripting Define Symbols and you can use it from code with
    Code (CSharp):
    1. #if UNITY_PIPELINE_URP
    2. #endif
    2. Making it work from a shader
    This should be added to the shader with the rest of the #pragma code.
    Code (CSharp):
    1. #pragma shader_feature UNITY_PIPELINE_URP
    It is important to use shader_feature because the pipelines are mutually exclusive.
    If you use multi_compile Unity will create all variants and trying to import files from non installed URP package will break the build.

    3. Enabling the keyword from code in editor
    From a ScriptableRendererFeature script in Create method add
    Code (CSharp):
    1. // NOTE: this is not sufficient for build, ShaderPreprocessor script is also needed
    2. var unityPipelineURP = GlobalKeyword.Create("UNITY_PIPELINE_URP");
    3. Shader.EnableKeyword(unityPipelineURP);
    That will not work in build but only in the editor because all variants exists in editor and you can switch them but once you build they get stripped.

    4. Enabling the keyword from build
    This code is only executed on build so it can't be a single place from where editor materials are also updated.
    Code (CSharp):
    1. #if UNITY_EDITOR
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Rendering;
    5. using UnityEditor.Rendering;
    6. using UnityEditor.Build;
    7.  
    8. class ShaderPreprocessor : IPreprocessShaders
    9. {
    10.     public int callbackOrder { get { return 0; } }
    11.  
    12.     public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data)
    13.     {
    14.         if (shader.name.Contains("YourShaderName"))
    15.         {
    16.             for (int i = 0; i < data.Count; ++i)
    17.             {
    18.                 #if UNITY_PIPELINE_URP
    19.                 var keyword = new ShaderKeyword("UNITY_PIPELINE_URP");
    20.                 if (!data[i].shaderKeywordSet.IsEnabled(keyword))
    21.                     data[i].shaderKeywordSet.Enable(keyword);
    22.                 #endif
    23.             }
    24.         }
    25.     }
    26. }
    27. #endif
    28.  

    Why is setting global keywords not persisted somewhere like with Scriptable Define Symbols or local ones serialized with the material and then skipped from stripping if enabled?

    I need to sleep.
     
    ekakiya and funkyCoty like this.
  19. ImpossibleRobert

    ImpossibleRobert

    Joined:
    Oct 10, 2013
    Posts:
    530
    This is quite a mess. I don't get Unity's argumentation of "you should not know". What I hear them say is "We don't care and we have no clue why someone would ever need such". I am writing an editor mode tooling to import models and I need to do things differently, e.g. calling the converter, depending on the pipeline. The converter is only available in URP packages so if these are not installed code does not compile. I don't want to set arbitrary compiler symbols in my users project just to have some custom workaround. There should be a stable Unity solution for this that fully supports a C# workflow and not just UIs Unity provides ala SG.
     
    lordofduct and joshcamas like this.
  20. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    121
    I've improved on the detection by using assembly definition and based on the presence of urp library a define symbol can be added conditionally, but that is only a replacement for the Editor folder gist part of my previous post, the rest is still needed.

    I'm wondering, how are you calling the converter through code?
     
    ImpossibleRobert likes this.
  21. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    481
    Maybe this helps? Unity has means to check if you have installed a package and you can query the setting if you have an URP setting asset in the settings (which means you are using URP), the same with HDRP.
    https://forum.unity.com/threads/urp-package-defines.936371/#post-6117590
     
    ImpossibleRobert likes this.
  22. ImpossibleRobert

    ImpossibleRobert

    Joined:
    Oct 10, 2013
    Posts:
    530
    This is actually a really good solution! I didn't know about this and it adds a lot of possibilities now. For those wondering how to configure it: one needs to install the package at least once to select the resource but can then deinstall it again.

    upload_2024-3-13_17-53-24.png
     
    Lurking-Ninja likes this.
  23. ImpossibleRobert

    ImpossibleRobert

    Joined:
    Oct 10, 2013
    Posts:
    530
    See at the bottom "using API"

    https://docs.unity3d.com/Packages/c...versal@15.0/manual/features/rp-converter.html
     
    Radivarig likes this.