Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Remove FilmGrain textures in 2020 without disabling Post-Processing

Discussion in 'Universal Render Pipeline' started by bigbrainz, Aug 17, 2021.

  1. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    175
    Currently URP is adding a dozen, very large FilmGrain post-processing textures to every scene bundle in WebGL. Our clients are very sensitive to download size and this useless addition of 3MB+ can often double our bundle sizes. It's a big problem because we have to fight so hard to optimize every inch of every texture, then this comes along and blows our budget completely.

    This has been discussed with much frustration in other threads generally, as well as in at least one bug fix.

    However, we want to use SOME Post-Processing, like Bloom and HBAO, so a fix that requires disabling all Post-Processing will not help. I also understand that the fix to do that will not be back-ported to 2020, so that also wouldn't help us.

    Our urgent need is to be able to just remove the `FilmGrain` textures from our builds. We used to be able to solve the problem by simply removing or shrinking those textures, but Unity's gotten more and more "helpful" such that we can no longer do either of those things--it keeps repairing and adding them back in.

    Can anyone please help us find a way to either remove, shrink, or compress these textures?

    upload_2021-8-17_15-10-47.png
     
  2. xgonzal2

    xgonzal2

    Joined:
    Jul 3, 2012
    Posts:
    62
    No straightforward way of doing this as far as I know since all the relevant fields and functions are marked internal. I have done something similar but I have a modified URP package for other reasons so the internal API wasn't a problem. That said I tried doing it without modifying too much of the codebase so I think the process below should work.

    What I have is a custom class that inherits from IPreprocessBuildWithReport. Then in the OnPreprocessBuild function I can get access to the URP assets in the project. The textures you are talking about are referenced in the post process data scriptable object which should be accessible from the ForwardRendererData object that the URP asset has via its m_RendererDataList field. Then just null out the references to those textures and that should be enough for the build to not package them. Of course nulling them out could open up the possibility of issues in the build if something happens to use it so just watch out for that.

    The issue is m_RendererDataList is marked internal so you would need reflection to get access to it and then you should be able to do what I did above.

    https://forum.unity.com/threads/no-access-to-pipelines-rendererdatalist.781154/ has an example of using reflection to access m_RendererDataList.

    I think I remember seeing some other post that had a script for reducing the file size of those textures but don't remember where it may be.

    Hope it helps!
     
  3. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    175
    Sounds good--thank you! I'll see if one of our smart guys can digest what you've done there and get it working for us.

    I've also created a bug report on the issue. I'm sure it's a super easy thing for Unity to address--we'll just have to see if if they decide to take the time for it.

    We had a script that used to do something similar to what you're describing for 2019, but 2020 got too smart for it. Here's that script just in case it's helpful to someone as a reference.

    Code (CSharp):
    1. using System.IO;
    2. using UnityEditor;
    3. using UnityEditor.Build;
    4. using UnityEditor.Build.Reporting;
    5. using UnityEngine;
    6.  
    7. public class RemoveURPTextures : IPreprocessBuildWithReport
    8. {
    9.     public int callbackOrder { get { return 0; } }
    10.     public void OnPreprocessBuild(BuildReport report)
    11.     {
    12.         Debug.Log("MyCustomBuildProcessor.OnPreprocessBuild for target " + report.summary.platform + " at path " + report.summary.outputPath);
    13.  
    14.         string packagesPath = Application.dataPath.Replace("/Assets", "") + "/Library/PackageCache";
    15.         Debug.Log($"packagesPath: {packagesPath}");
    16.         string[] directories = Directory.GetDirectories(packagesPath);
    17.  
    18.         foreach (string directory in directories)
    19.         {
    20.             Debug.Log($"directory: {directory}");
    21.             if (directory.Contains("com.unity.render-pipelines.universal"))
    22.             {
    23.                 Debug.Log($"Modifying entries in: {directory}");
    24.                 string texturesPath = Path.Combine(directory, "Textures/FilmGrain");
    25.                 string[] files = Directory.GetFiles(texturesPath, "*.meta");
    26.                 foreach (string filename in files)
    27.                 {
    28.                     Debug.Log($"Modifying entry: {filename}");
    29.                     string[] lines = File.ReadAllLines(filename);
    30.  
    31.                     for (int i = 0; i < lines.Length; i++)
    32.                     {
    33.                         lines[i] = lines[i].Replace("maxTextureSize: 2048", "maxTextureSize: 32");
    34.                     }
    35.  
    36.                     File.WriteAllLines(filename, lines);
    37.                 }
    38.             }
    39.         }
    40.         //throw new BuildFailedException("aa");
    41.  
    42.         foreach (string directory in directories)
    43.         {
    44.             Debug.Log($"directory: {directory}");
    45.             if (directory.Contains("com.unity.render-pipelines.universal"))
    46.             {
    47.                 Debug.Log($"Modifying entries in: {directory}");
    48.                 string texturesPath = Path.Combine(directory, "Textures/SMAA");
    49.                 string[] files = Directory.GetFiles(texturesPath, "*.meta");
    50.                 foreach (string filename in files)
    51.                 {
    52.                     Debug.Log($"Modifying entry: {filename}");
    53.                     string[] lines = File.ReadAllLines(filename);
    54.  
    55.                     for (int i = 0; i < lines.Length; i++)
    56.                     {
    57.                         lines[i] = lines[i].Replace("maxTextureSize: 2048", "maxTextureSize: 32");
    58.                     }
    59.  
    60.                     File.WriteAllLines(filename, lines);
    61.                 }
    62.             }
    63.         }
    64.     }
    65. }
     
  4. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    175
    So we're finding that this isn't helping us with Asset Bundles because OnPostprocessBuild isn't affecting those. Hmmm...
     
  5. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    175
    @xgonzal2, It looks like we're getting access to the m_RendererDataList that you referred to, but could not get the ForwardRendererData. Any tips?
     
  6. xgonzal2

    xgonzal2

    Joined:
    Jul 3, 2012
    Posts:
    62
    The renderer data list is an array of ScriptableRendererData which the ForwardRendererData derives from. So you can iterate through the array and type cast each entry to ForwardRendererData while checking for null. If it isn't null then you have a reference to a ForwardRendererData and that has a public field for the post process data. That post process data is what stores all the textures you are trying to remove. I added a snippet of what my script does below. I should say that I haven't tried this with asset bundles or addressables yet so I can't guarantee it works there. In a build without any of those I can see none of these textures make it to the build through the editor log after the build is done.

    Code (CSharp):
    1.         private void StripBuiltinUnityPostProcessTextures(ref List<UniversalRenderPipelineAsset> urps)
    2.         {
    3.             foreach (UniversalRenderPipelineAsset urp in urps)
    4.             {
    5.                 foreach (ScriptableRendererData srd in urp.m_RendererDataList)
    6.                 {
    7.                     UniversalRendererData data = srd as UniversalRendererData;
    8.                     if (data == null)
    9.                         continue;
    10.  
    11.                     data.postProcessData.textures = null;
    12.                 }
    13.             }
    14.         }
     
  7. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    175
    Boom! In the end I guess it was pretty simple, but we were very unfamiliar with it, so it took some time to figure it out, but your tips worked and it shrunk the textures in our main build 60%. Nice! Thank you!

    We thought it would be in the OnPostprocessBuild, but when we look at the debugs, it seems it's actually happening in the OnPreprocessBuild, so we actually removed that call (but I left it in here just for reference). Hopefully this can help someone else along the way

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Rendering.Universal;
    4.  
    5. #if UNITY_EDITOR && UNITY_WEBGL
    6. using UnityEditor.Build;
    7. using UnityEditor.Build.Reporting;
    8.  
    9. public class PostDataProcessor : IPostprocessBuildWithReport, IPreprocessBuildWithReport
    10. {
    11.     public int callbackOrder { get { return 0; } }
    12.  
    13.     public void OnPreprocessBuild(BuildReport report) => PostProcessData();
    14.  
    15.     public void OnPostprocessBuild(BuildReport report) => PostProcessData();
    16.  
    17.     void PostProcessData()
    18.     {
    19.         ScriptableRendererData[] rendererDataList = (ScriptableRendererData[])typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(UniversalRenderPipeline.asset);
    20.  
    21.         for (int i = 0; i < rendererDataList.Length; i++)
    22.         {
    23.             ForwardRendererData frd = (ForwardRendererData)rendererDataList[i];
    24.             if (frd != null)
    25.             {
    26.                 frd.postProcessData.textures = null;
    27.             }
    28.         }
    29.     }
    30.  
    31. }
    32. #endif
    33.  
     
  8. Grandtrine

    Grandtrine

    Joined:
    Jul 27, 2018
    Posts:
    9
    Has anyone seem to solve this issue of blue noise and filmgrain , its taking about 3mb in my project ?
     
  9. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    175
    Is something about the above solution not working for you?
     
  10. duongpq

    duongpq

    Joined:
    May 12, 2022
    Posts:
    1
    For anyone who is still struggling, I resize textures in C:\Users\admin\AppData\Local\Unity\cache\packages\packages.unity.com\com.unity.render-pipelines.universal@10.10.1 and Library/ShaderCache/...
    It works perfectly
     
  11. TheNullReference

    TheNullReference

    Joined:
    Nov 30, 2018
    Posts:
    222
    This did not work as of September 2023.

    Something like this works. I went to the package manager, found the textures -> Open in Explorer and then resized them outside of Unity.

    First time I try they rebuilt as the package 'validated'. Second try seemed to stick.