Search Unity

Question Graphics.Blit with HDRP Shadergraph

Discussion in 'Shader Graph' started by A132LW, Aug 8, 2019.

  1. A132LW

    A132LW

    Joined:
    Jun 21, 2017
    Posts:
    37
    As MR-Heavy originally asked on the shadergraph thread - with no answer as far as I know:

    "Is it any good way to force "Graphics.Blit(Texture2D, RenderTexture, Material); " work with shader graph's unlit shader?"


    @MR-Heavy, have you found a solution yet? I tried wyatttt 's method and got your results.

    @wyatttt, do you have any more ideas?


    All suggestions are appreciated.
    HDRP and Shadergraph on 6.9.1 in 2019.2.0b9. Can upgrade if necessary.
     
  2. nikefootbag

    nikefootbag

    Joined:
    Jun 13, 2017
    Posts:
    28
    I'm not sure if this is related to the issue I had with Graphics.Blit not working, but in the end I used Unity's CustomRenderTexture to get shadergraph to write to a texture.

    To elaborate, I was making a Snow Track shader for car wheels, and was using one shader graph to paint to a texture(aka splatmap) based on wheel positions, then another shader graph to read from that texture and displace the snow.

    The Custom Render Texture takes in a material that uses the ShaderGraph you're wanting to blit with. You can then use that Custom Render Texture as an input to another ShaderGraph (in my case, a Snow Displacement Shadergraph).

    On the Custom Render Texture, you can set it's updateMode to "OnDemand", and tell it to Update whenever you would call Graphics.Blit.

    In my case of SnowTracks, this would be each fixed update frame, raycasting wheel positions then sending those positions to the CustomRenderTexture DrawTracks shadergraph, which updates the RenderTexture and is then used to the SnowTracks Displacement shadergraph.

    I uploaded the project to github also: https://github.com/tim-neville/Snow-Tracks-ShaderGraph-Unity-2019.1

    Snap.png

    Snap2.png
     
    Neiist, _slash_, Ne0mega and 4 others like this.
  3. A132LW

    A132LW

    Joined:
    Jun 21, 2017
    Posts:
    37
    Thank you so much! This is exactly what I was looking for.
     
    nikefootbag likes this.
  4. nikefootbag

    nikefootbag

    Joined:
    Jun 13, 2017
    Posts:
    28
    No problem, glad I could help!
     
  5. A132LW

    A132LW

    Joined:
    Jun 21, 2017
    Posts:
    37
    So, for some reason, the HDRP unlit shadergraph, as well as any other material created by the default HDRP shaders, fails to update a custom render texture.
    This is probably due to these specifications:

    The only mandatory steps when writing a shader for a custom texture are:

    * #include “UnityCustomRenderTexture.cginc”

    • Use the provided Vertex Shader
      CustomRenderTextureVertexShader

    • Use the provided input structure v2f_customrendertexture for the pixel shader

    When I use the example custom render texture shader; however, the render texture works perfectly.

    Thank you for the help. I will ask around to see if someone has a workaround.
     
  6. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
  7. nikefootbag

    nikefootbag

    Joined:
    Jun 13, 2017
    Posts:
    28
    @rizu Yes they're free to use, I just added the MIT licence to the repo aswell for clarity. Thanks for asking!
     
    rz_0lento likes this.
  8. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    You can use regular (nonHDRP) unlit shadergraph with HDRP. I quickly ported nikefootbag's sample to HDRP by just changing the SRP asset to HDRP asset from graphics settings, swapping the regular shaders to HDRP/Lit and recompiled/resaved the unlit shadergraphs used for drawing the tracks (didn't port them to HDRP unlit at all).

    Just to clarify this: those regular shadergraphs are all compatible with HDRP, you can think them as generic/universal graphs that work on both SRP pipelines, only HDRP shadergraphs are specific to one SRP.
     
    A132LW likes this.
  9. A132LW

    A132LW

    Joined:
    Jun 21, 2017
    Posts:
    37
    Thank you rizu. Since nikefootbag's solution did not work in my HDRP-based project, I had incorrectly assumed that HDRP did not yet work with custom render textures. I have tried with the unlit (non-HDRP specific) shadergraph as well - so it must be an issue with my project.
     
  10. A132LW

    A132LW

    Joined:
    Jun 21, 2017
    Posts:
    37
    Update: Custom render textures only work with LWRP, not HDRP, unless both packages are installed in the same project and the unlit master node is used.
     
    zyzyx likes this.
  11. cr4y

    cr4y

    Joined:
    Jul 12, 2012
    Posts:
    44
    I had the same issue. It's clearly a bug in Unity, so I've reported it. Now you can vote for fixing it here!
     
  12. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    No comment on Graphics.Blit but CRT definitely works on both URP and HDRP. This is relatively old thread but wanted to give some update now that the thread has been bumped. Basically URP Unlit and old style CRT shaders work as is on HDRP but it's challenging to get URP shader itself to HDRP as you need to have both URP and HDRP installed for this to work.

    You can still use old style CRT shaders as shown in official docs for CRT. If you want node graph shader for CRT you can use Amplify Shader Editor as it has special CRT support. This also works with HDRP.
     
    Ne0mega and A132LW like this.
  13. Oxeren

    Oxeren

    Joined:
    Aug 14, 2013
    Posts:
    121
    If it helps anyone, CommandBuffer.Blit does work with shader graph shaders, at least in URP.
     
    oleg_v likes this.
  14. cr4y

    cr4y

    Joined:
    Jul 12, 2012
    Posts:
    44
    @rz_0lento What do you mean by "CRT shaders"? I don't recognize the term :(
    @Oxeren thanks for sharing this! How do you use it? Do you add the custom render pass? Maybe you would have some code to share, please?
     
  15. Oxeren

    Oxeren

    Joined:
    Aug 14, 2013
    Posts:
    121
    I've used it in scriptable renderer features/passes. Here is an example of a pass that uses it. Check out the rest of the repository to see how the pass is used in the scriptable renderer feature.
     
  16. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Ne0mega likes this.
  17. chmodseven

    chmodseven

    Joined:
    Jul 20, 2012
    Posts:
    120
    In case it helps someone, I eventually cobbled together (from various tips including the ones on this thread) a CustomRenderTexture solution for URP blitting. I expect it should work with HDRP too although I haven't tested that.

    My use case was that I needed to copy the texture out of a material with a ShaderGraph shader I wrote that produces fBM noise, but Graphics.Blit wasn't working and I couldn't figure out how to make CommandBuffer.Blit work either. Finally I got it working with the CustomRenderTexture tip. The script below has some extra guff for timings and storing the resulting texture into a canvas RawImage I was using to test; those can be safely stripped out if all you care about is the GetTextureFromShaderGraphBasedMaterial method. You could probably also keep the CRT around and use Update() instead of recreating it for each refresh, if memory isn't an issue.

    Code (CSharp):
    1. using System.Diagnostics;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using Debug = UnityEngine.Debug;
    5.  
    6. public class ShaderGrab : MonoBehaviour
    7. {
    8.     public int width = 100;
    9.     public int height = 100;
    10.     public RawImage displayImage;
    11.    
    12.     private Material _material;
    13.     private Stopwatch _sw;
    14.     private bool _isProcessing;
    15.     private readonly int _mainTex = Shader.PropertyToID ("_MainTex");
    16.     private const bool ShowDebugTimings = true;
    17.  
    18.     private void Start ()
    19.     {
    20.         if (ShowDebugTimings)
    21.         {
    22.             _sw = new Stopwatch ();
    23.         }
    24.         MeshRenderer meshRenderer = GetComponent<MeshRenderer> ();
    25.         _material = meshRenderer.sharedMaterial;
    26.         SetDisplayTexture ();
    27.     }
    28.  
    29.     private void Update ()
    30.     {
    31.         if (Input.GetKeyDown (KeyCode.Space))
    32.         {
    33.             SetDisplayTexture ();
    34.         }
    35.     }
    36.  
    37.     private void SetDisplayTexture ()
    38.     {
    39.         if (ShowDebugTimings)
    40.         {
    41.             _sw.Restart ();
    42.         }
    43.         displayImage.texture = GetTextureFromShaderGraphBasedMaterial (_material, width, height);
    44.         if (ShowDebugTimings)
    45.         {
    46.             _sw.Stop ();
    47.             Debug.Log ("Processing completed in " + _sw.ElapsedMilliseconds.ToString ("N0") + " ms");
    48.         }
    49.     }
    50.  
    51.     private Texture GetTextureFromShaderGraphBasedMaterial (
    52.         Material shaderBasedMaterial, int outputTextureWidth, int outputTextureHeight)
    53.     {
    54.         CustomRenderTexture crt = new CustomRenderTexture (
    55.             outputTextureWidth, outputTextureHeight, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear)
    56.         {
    57.             updateMode = CustomRenderTextureUpdateMode.OnDemand,
    58.             material = shaderBasedMaterial,
    59.             initializationSource = CustomRenderTextureInitializationSource.Material,
    60.             initializationMaterial = shaderBasedMaterial
    61.         };
    62.         shaderBasedMaterial.SetTexture (_mainTex, crt);
    63.         crt.Initialize ();
    64.         crt.Release ();
    65.         return crt.material.mainTexture;
    66.     }
    67. }
     
    Last edited: Feb 5, 2022
  18. Bers1504

    Bers1504

    Joined:
    Apr 28, 2018
    Posts:
    17
    For those interested:

    Unity 2021.2 - Preferred solution

    Blitting a BuiltIn Unlit Shader Graph to a RenderTexture can work with the High Definition Render Pipeline since Unity 2021.2, without any trickery. At least as far as I know, it also works with URP, HDRP and the BuiltIn pipeline, on Windows.

    upload_2022-5-3_14-46-9.png

    Then, you can just call Graphics.Blit() with a material using that Unlit Shader Graph.
    e.g.
    Code (CSharp):
    1. Graphics.Blit(null, targetRenderTexture, myShaderGraphMaterial, 0);
    Not sure if that solution works on all platforms or with all possible render pipeline settings, please comment below if you happen to know.

    I could create a repo with a working solution demo, if someone asks for it.

    Previous versions (Unity 2019 - 2021.1) - Alternate solution

    In previous versions, a simple (yet hackish) solution for Graphics.Blit to work with HDRP Unlit Shader Graphs can be found here: https://github.com/Bers1504/unity-hdrp-shadergraph-blit

    That repo contains a custom function node that can be added to an unlit HDRP Shader Graph, which works as a patch for fixing the broken HDRP ShaderGraph Blit. The problem is related to model / view matrices, which aren't properly set up for the blit quad to correctly fill the viewport. It seems the values from the last active camera are used in the model view matrix when blitting, which is probably wrong. The camera-relative rendering setting also seems to be part of the problem, as the blit quad vertices are incorrectly changed when that feature is active in the project rendering settings.

    As a workaround, the HDRP model, view and projection matrices as well as the functions to transform vertices to clip space are overridden with values that are known to work with blitting. To achieve this, a custom function patch node is added in the shader graph, and its sole purpose is to provide an injection point for overriding matrices in the final actual shader, generated from the Shader Graph (yes, that is super hacky and fragile as it assumes a certain shader code expansion order and also assumes undocumented transformation function names - use at your own risks!).

    Anecdotally, without this patch, it is sometimes possible to see a tiny misplaced quad being rendered, when calling Graphics.Blit() while the last active camera happens to be at (0,0,0).

    Finally, a reminder that Built-In Unlit Shader Graph are known to work in Unity 2021.2 without this ugly patch, so you should really use the first, preferred solution if you can.[/code]
     
    nikefootbag and chmodseven like this.
  19. cr4y

    cr4y

    Joined:
    Jul 12, 2012
    Posts:
    44
    Not really, but...

    For Unity 2021.3.4, the line Graphics.Blit(null, targetRenderTexture, myShaderGraphMaterial, pass);
    • HDRP - Unlit shadergraph - does not work
    • HDRP Lit shadergraph - does not work
    • URP Unlit shadergraph - works for parameter pass = 0
    • URP Lit shadergraph - works for parameter pass = -1 and also for pass = 1
    • Built-in Unlit shadergraph - works for parameter pass = 0
    • Built-in Lit shadergraph - works for parameter pass = 2
    Disclaimer: it does work like mentioned above, but I have not found any documentation telling why. No idea why it fails for HDRP either. If someone would know, please tell
     
    Bers1504 likes this.
  20. Bers1504

    Bers1504

    Joined:
    Apr 28, 2018
    Posts:
    17
    HDRP shadergraphs fail to render properly with Graphics.Blit() mainly because object and view projection matrices used by these shaders are improperly set by Unity (it is unsupported, for now). Additionally, the camera-relative rendering option can also mess with these matrices.

    I was able to verify this by generating the shader code of an unlit HDRP shader graph, then hard-coding the matrices and transformation functions as follow:

    Code (CSharp):
    1.  
    2. #define UNITY_MATRIX_VP float4x4(2, 0, 0, -1, 0, -2, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1)
    3. #define UNITY_MATRIX_M  float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
    4.  
    5. float3 TransformObjectToWorld_NotCameraRelative(float3 positionOS)
    6. {
    7.   float4x4 m = UNITY_MATRIX_M;
    8.   return mul(UNITY_MATRIX_M, float4(positionOS, 1.0)).xyz;
    9. }
    10. #define TransformObjectToWorld TransformObjectToWorld_NotCameraRelative
    11.  
    12. float4 TransformWorldToHClip_BlitSupport(float3 positionWS)
    13. {
    14.   // Transforms position from world space to homogenous space
    15.   return mul(UNITY_MATRIX_VP, float4(positionWS, 1.0));
    16. }
    17. #define TransformWorldToHClip TransformWorldToHClip_BlitSupport
    18.  
    With these matrices, blitting an unlit HDRP shadergraph works with pass = 6 "ForwardOnly" (successfully tested in 2019.1, 2019.3, 2021.3.4f1).

    DISCLAIMER: I'm not suggesting this is a proper fix, just giving out the reason why Graphics.Blit() it is not working. The test above only proves that Blit() could work with HDRP shadergraphs, if shader matrices were set properly by Unity.
    Check this repo if you want to test it for yourself, the example HDRP shadergraph works with 2021.3.4f1 on windows with a matrix hack).
     
    Last edited: Jun 13, 2022
    Gooren likes this.
  21. Bers1504

    Bers1504

    Joined:
    Apr 28, 2018
    Posts:
    17
    Thanks cr4y for testing the URP shadergraph, that's useful information!

    Additional note : blitting a Built-in Unlit shadergraph works with all rendering pipelines on windows AFAIK, including HDRP. That was what I meant in my original message, if that wasn't clear. HDRP shadergraphs are incompatible with Graphics.Blit() though, unless you tamper with matrices, as described above and reported by cr4y.
     
    Last edited: Jun 13, 2022
    Thaina, Folstrym and Gooren like this.