Search Unity

URP and Standard Tonemapped Lit Shader without postprocessing (for Oculus Quest or mobile)

Discussion in 'Universal Render Pipeline' started by atomicjoe, Jan 21, 2021.

?

Was this usefull for you?

  1. YES!

    20 vote(s)
    100.0%
  2. NO

    0 vote(s)
    0.0%
  1. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    UPDATE: Now it includes a version of the shader for the Standard Builtin Pipeline + an example on how to implement it on a custom surface shader.
    If you want to use with the builtin pipeline, just delete the URP folder to avoid compilation errors and use the "Tonemapped Standard" shader instead of the "Standard" shader.

    This shader is a simple modification of the Universal Render Pipeline Lit shader to allow for tonemapping and color correction without having to use any postprocessing effect and without using HDR buffers.

    All color corrections are applied inside the shader, so you don't even need to use HDR in the camera to have nice color corrected tonemapped images. (although the shader is compatible with HDR in case you want to use postprocesses like Bloom or Glow)

    This is specially important for the Oculus Quest, since you can't do postprocessing effects on it.

    Just import the package and replace all "Lit" shaders in your materials with the supplied "Universal Render Pipeline/Tonemapped Lit" and put the included "Tonemapped Lit Controller" prefab in your scene to control the color correction.

    DOWNLOAD IT HERE FOR Unity 2019 (only URP)

    DOWNLOAD IT HERE FOR Unity 2020.3.2f1 LTS (URP + Built-in Standard)

    Color correction adjustments available:
    - Color Filter
    - Gamma
    - Contrast
    - Brightness
    - Saturation
    - Hue Shift (trippy effect)

    Of course, you can modify those adjustments in realtime in your game to match the mood of each zone ;)

    WARNING! Be sure to disable the color correction before rendering lightmaps!
    Otherwise the lightmaps colors will be off!


    Limitations: Keep in mind this is only the regular Lit shader. Any other shader like the skybox shader would need to be modified to include the same color corrections. Although you only have to include the "TonemappedLitColorCorrection_Include.hlsl" in the shader an use the function "TonemappedLitColorCorrection(color)" to apply the global color corrections to any custom shader.
    Also, since the shadergraph doesn't expose any way (that I know) to modify the final output color, any custom shadergraph shader will not be compatible with this and just render without color correction.
    Take a look at the shader file "LitForwardPass.hlsl" to see how to implement it in other shaders. (from '#include "TonemappedLitColorCorrection_Include.hlsl" ' to the end)

    Some examples:







    this is using negative gamma, negative brightness, saturation boost and hue shift to correct the color:
    Notice how the hue of the color is the same as the original render but the luminosity has been inverted. That would be cool for a comic book effect.

    v1.01: Added Hue Shift and some minor QoL mods.
    v1.02: Removed URP dependencies in the shader. This should make it easier to add in non URP specific shaders.
     
    Last edited: Apr 5, 2021
    SuperRaffles, sisermann, m4d and 2 others like this.
  2. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Amazing, I am definately giving this a try, you cheeky digital rascal, you :D
     
    atomicjoe likes this.
  3. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Let's hope someone at Unity sees this and exposes a way to modify the final output color of the shadergraph master node with custom functions.
     
    tspk91, Martin_H and hippocoder like this.
  4. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    It seems like such an obvious omission. I cannot imagine a single person not wanting this, and not just for VR.
     
  5. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Well, there is some performance penalty in this shader, since it has to convert from RGB to Hue Saturation and Value space color and back, also there is a "pow" in there to apply the gamma correction, and power functions are really expensive on mobile.
    All of this can make this shader more expensive if you do a lot of overdraw in your scene, although if you do a lot of overdraw, you have bigger issues to deal with... lol
    On desktop or consoles, the performance difference is negligible. On mobile, depending on the GPU, it will be slightly slower than applying a fullscreen effect if you were going to do some Glow or Bloom anyway (that's the case of the TegraX1 in the Switch. The TegraX1 behaves more like a mini desktop GPU than a mobile one. It is thus very comfortable using fullscreen postprocesses and grabpasses)

    However, for the Oculus Quest, it's the only solution and it's blazing fast :)

    EDIT: Oh, you were talking about exposing the final color in the shader graph! Well, yes, it's a really weird omission.
     
    hippocoder likes this.
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I mean both actually, I can't see anyone not wanting a solution like what you've developed. I'd probably be able to add valves dither as well with a bit of tinkering (it's kind of useless without final pixel as banding is caused by lighting).
     
    tspk91 likes this.
  7. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Oh! I forgot to specify it but, you NEED to disable the color correction before rendering your lightmaps!
    There is a checkbox to enable and disable the effect in the shader controller script.
     
    hippocoder likes this.
  8. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    I just added Hue Shift and some minor improvements (tooltips and minor refactoring)
    I also removed the 0 limit for gamma, since it can be useful to go negative to have negative image effects :)



    this is using negative gamma, negative brightness, saturation boost and hue shift to correct the color:
     
    Last edited: Jan 22, 2021
    hippocoder likes this.
  9. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Updated to remove URP dependencies in the shader.
    This should make it easier to add in non URP specific shaders.
     
  10. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    That latest one seems to cause errors in latest 2020.2f2. Can't trace where it's from as it causes some error in URP according to the console (seems Unity's got a lot worse at figuring out where errors come from recently).

    Please try a fresh 2020.2f2 project - mine is mostly empty and I'll try again in an empty one soon.
     
  11. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    They probably changed the URP lit shader.
    Not a problem, I'll fix it later.
     
    hippocoder likes this.
  12. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Just having a nose now, it's bewildering if you haven't dived deep before. How do you even navigate this stuff ? :)
     
    atomicjoe likes this.
  13. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Yeah, it would be great if we had the docs of the actual code. Otherwise it's a nightmare to navigate it.
    That's why I did my own uber shader for regular built-in forward renderer with single pass lighting.
    And it ended up being both faster and prettier than URP because I only had to support the features I actually use and I could implement others that aren't present by default, like specular lighting from lightmapped textures and lightprobes, anisotropy, fake subsurface scattering and iridescence. Plus it's retrocompatible with built-in standard content, unlike URP and HDRP.
    I really don't like the current state of the render pipelines.
    I just installed Unity 2020.2.2f1, I'll fix it now.
     
    hippocoder likes this.
  14. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Fixed.
    They changed quite a lot of things in URP's lit shader.
    I have uploaded a new version for Unity 2020.2.2f1 and higher but have left the 2019 version because it could be handy for someone on the LTS.
     
    hippocoder likes this.
  15. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    You will have to delete the whole folder and import the new package to avoid errors.
    Also, you may have to reassign the tonemapped Lit URP shader to your materials in case they still show pink after that.
    (the shader is named the same, but it didn't automatically reassign the shader to the materials in my project. I don't know why.)
     
    hippocoder likes this.
  16. UnityMaru

    UnityMaru

    Community Engagement Manager PSM

    Joined:
    Mar 16, 2016
    Posts:
    1,227
    Fantastic work with this :)
     
    atomicjoe likes this.
  17. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Thanks! But what we really need is a way to modify the final color in the shader graph master node. Otherwise we can't do things like that in shaders made with the shader graph.
    If you could bring this to the attention of the shader graph team, THAT would be fantastic ;)
     
  18. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    +1
     
  19. UnityMaru

    UnityMaru

    Community Engagement Manager PSM

    Joined:
    Mar 16, 2016
    Posts:
    1,227
    Without doubt, already planned.

    Without TMI, I'm working some of that Package Manager love within the Graphics forums these days to make sure we can get some more feedback acknowledged.
     
    atomicjoe and hippocoder like this.
  20. raydentek

    raydentek

    Joined:
    Jul 27, 2016
    Posts:
    103
    @atomicjoe Looks great. Do you think anything like can be done for built-in pipeline? :D Thanks for tips!
     
  21. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Of course! This is actually ported from my built-in pipeline shaders.
    With Surface Shaders, you can modify the final color of the rendered pixel using a specified function. Look for FINAL COLOR in Surface Shaders docs.
     
    raydentek likes this.
  22. raydentek

    raydentek

    Joined:
    Jul 27, 2016
    Posts:
    103
    Thanks for confirming! I will look into it.
     
  23. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    I have updated the package to include a Builtin Standard Pipeline Tonemapped-Standard shader and an example of custom surface shader with the effect applied.
    If you want to use it in a project without URP, just delete the URP folder to avoid compiler errors and use the new "Tonemapped Standard" shader instead of the "Standard" shader in your materials. ;)

    I haven't actually tested it, but it should work.
    Please test it and report back :p:D
     
    raydentek likes this.
  24. raydentek

    raydentek

    Joined:
    Jul 27, 2016
    Posts:
    103
    @atomicjoe Thanks for sharing! That's a great plan, I will test it out in a moment.
     
  25. raydentek

    raydentek

    Joined:
    Jul 27, 2016
    Posts:
    103
    Tested in Built-in and URP and both work as per instructions. Thanks @atomicjoe tonemappedStandardShaderTest1.jpg
     
    atomicjoe likes this.
  26. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
     
    raydentek likes this.
  27. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,756
    if you get a single instanced water shader for VR on built-in... i'll pay!
     
  28. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    There is already a lot of great water shaders in the store for built-in and URP.
    If they can't manage single pass VR, then I will not be able to do it either.
    I know there were issues with the reflections being wrong on VR single pass, but I don't know if it was fixed on Unity's side or not.
    Some times you just have to deal with the limitations and move on: instead of realtime reflections using another camera, you can fake it using reflection probes , distorting the water a lot with normalmaps and setting the material as super specular shiny.
     
  29. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,756
    As far as I know, only R.A.M is able to do it on built-in. But the performance on mobile is super bad. Lux Water is awesome in performance but it can´t do single pass.
     
  30. vincentwing

    vincentwing

    Joined:
    Aug 7, 2017
    Posts:
    2
    I'm using this for my project, and I had to edit a few shaders to use tonemapping. No sense in hoarding them for myself, so here they are attached to this post as a unitypackage.

    Included:
    upload_2021-7-8_11-27-42.png

    • The unlit shaders are a copy-paste from Unity's guide to writing custom URP shaders.
    • The vertex color shaders are from Polybrush's sample assets.
    • The skybox shader is generated from an included shader graph.
      • This one might be a bit wonky for your use, since I inverted the world y position. If needed, I would suggest editing the shader graph to not invert the y, generate the code, and make the same changes I made to the original file.

    All shader graphs that I generated code from are included.

    Here's the script I used to quickly update the project's shaders, slightly modified from this Unity Answers:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. public class ShaderOccurenceWindow : EditorWindow
    6. {
    7.     [MenuItem("Tools/Shader Occurence")]
    8.     public static void Open()
    9.     {
    10.         GetWindow<ShaderOccurenceWindow>();
    11.     }
    12.     Shader shader;
    13.     List<string> materials = new List<string>();
    14.     Vector2 scroll;
    15.     void OnGUI()
    16.     {
    17.         Shader prev = shader;
    18.         shader = EditorGUILayout.ObjectField(shader, typeof(Shader), false) as Shader;
    19.         if (shader != prev){
    20.             string shaderPath = AssetDatabase.GetAssetPath(shader);
    21.             string[] allMaterials = AssetDatabase.FindAssets("t:Material");
    22.             materials.Clear();
    23.             for (int i = 0; i < allMaterials.Length; i++){
    24.                 allMaterials[i] = AssetDatabase.GUIDToAssetPath(allMaterials[i]);
    25.                 var material = AssetDatabase.LoadAssetAtPath<Material>(allMaterials[i]);
    26.                 if (material.shader == shader)
    27.                     materials.Add(allMaterials[i]);
    28.             }
    29.         }
    30.         if (materials.Count > 0 && GUILayout.Button("Select All")){
    31.             List<Object> allMatObjects = new List<Object>();
    32.             for(int i = 0; i < materials.Count; ++i){
    33.                 Object obj = AssetDatabase.LoadMainAssetAtPath(materials[i]);
    34.                 if (obj is Material && !materials[i].StartsWith("Packages"))
    35.                     allMatObjects.Add(obj);
    36.             }
    37.             Selection.objects = allMatObjects.ToArray();
    38.         }
    39.         scroll = GUILayout.BeginScrollView(scroll);
    40.         {
    41.             for (int i = 0; i < materials.Count; i++){
    42.                 GUILayout.BeginHorizontal();
    43.                 {
    44.                     GUILayout.Label(Path.GetFileNameWithoutExtension(materials[i]));
    45.                     GUILayout.FlexibleSpace();
    46.                     if (GUILayout.Button("Show"))
    47.                         EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(materials[i], typeof(Material)));
    48.                 }
    49.                 GUILayout.EndHorizontal();
    50.             }
    51.         }
    52.         GUILayout.EndScrollView();
    53.     }
    54. }
     

    Attached Files:

    atomicjoe and hippocoder like this.
  31. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Very kind of you to share. But ultimately it's pretty bad actually it can't be done without hacks. I hope Unity is reading this and helps us do this in a way that does not require hacking.
     
    vincentwing and atomicjoe like this.
  32. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    That's the spirit! ;)
     
    sisermann likes this.
  33. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,756
    Did unity add a way to modify the final color in the shader graph master node at the end? I'm looking into trying URP again but I keep moving back to built-in because of so many different issues.
     
  34. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    727
    Guess it didn't work out?
     
  35. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    There is a wonderful idiom in French that describes what happens inside corporations like Unity when everything becomes unnecessarily complicated and basic user functionality gets the least priority:
     
  36. TrentSterling

    TrentSterling

    Joined:
    Jan 4, 2013
    Posts:
    99
    So I've been attacking Single Pass VR for quest 2 in 2019. Using built-in because I feel like URP never reached parity or performance of BiRP.

    Yeah I know, 2019 is old. But all the newer versions of Unity editor run worse and come with constant UI hangs that 2019 doesn't suffer from.

    Anyway I found this thread, and the ones around it very interesting. Thank you for providing the BiRP examples for unity 2020. Hopefully they'll work in 2019 without much work? If not I'll do some more reading about FinalColor.
     
  37. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    BiRP version should run without issues for any unity version down to Unity 5 and maybe even 4, so no worries there ;-)
     
    TrentSterling likes this.
  38. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    That's the magic of Surface Shaders and why I love them so much and hate SRPs with a passion. :)
     
    TrentSterling likes this.
  39. Noors84

    Noors84

    Joined:
    Jul 12, 2016
    Posts:
    78
    @atomicjoe Thanks for your shader. I've gone the LUT way using Unity's ApplyLut2D function in color.hlsl thinking it would be more optimized but i've read one of your post somewhere saying it was faster to do the color correction directly with some maths ?
    Also, would you guys know if there's a place to discuss about mobile VR graphics like a discord or something ?
    Thanks !
     
  40. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Doing the color correction directly in the shader can't be beaten in speed, since it doesn't have to copy the frame-buffer, read it back and apply the effect as a post-process does.

    Also, my method doesn't use LUTs because it would imply reading a texture (usually a 3D texture) for every pixel in the screen and doing so stresses the hardware much more than simply doing some math (plus it's more flexible and precise).

    But keep in mind this is only important for mobile in general and for the Quest specifically.
    On PC and consoles it can actually end up being a little slower than a post effect if you have a lot of overdraw or transparencies.

    Also, if you are using any type of post-process (as is usual on desktop), it would be faster to integrate the color correction function inside the post-process directly.

    About optimization for VR specifically, idk, but the graphics sub forum here is pretty great in general.
     
    Last edited: Mar 30, 2023
  41. Noors84

    Noors84

    Joined:
    Jul 12, 2016
    Posts:
    78
    Yes i meant i'm doing LUT correction in the shader, not post-process. Yeah i think it's 2 additional texture samples per pixel to filter the LUT texture. The target is mobile Focus 3 but it's similar to Quest 2 i guess.
     
  42. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Test both methods and benchmark: it's the only way to be sure really.
    Also, if you do, please post your results here. :)
     
  43. NexarChile

    NexarChile

    Joined:
    Apr 29, 2016
    Posts:
    17
    Hi @Noors84 !

    Could you please share an example of how to use Unity's ApplyLut2D function in a shader? I need to apply a LUT (haldclut) on a shader made with shader graph, but I don't know how to do it?

    Thanks in advance!