Search Unity

Asset Bundles and Shaders

Discussion in 'Asset Bundles' started by iseta, Jan 9, 2020.

  1. iseta

    iseta

    Joined:
    May 5, 2016
    Posts:
    48
    Hello!

    I've struggled a lot in the past few weeks with AssetBundles and shaders, and I'd like to share how I've managed to solve my issue, since it might help someone else. If you have any questions or feedback, please feel free to comment down below! :D

    Basically, my project contains a scene which is a hub to download a few augmented reality projects that my company has produced over the years. We've been using AssetBundles to reduce our build size, and each scene is a downloadable AssetBundle.

    Initially, we got a lot of shader errors when loading AssetBundles, so we decided to use "Always Included Shaders", which worked for a while, but then we started using a lot of different shaders and the build size (and time) increased a lot, the project itself was going over the 100mb+ limit.

    I've solved this by eliminating the "Always Included Shaders" and using Shader Preloading. Each project has it's .shadervariants file, which is loaded into the main project.

    How do you save a shadervariant?

    - Open the project where you're building your Asset Bundle

    - Go to Edit > Project Settings > Graphics and then aaaaall the way down to the "Save to asset..." button here
    upload_2020-1-9_10-25-8.png

    To use the .shadervariants file, copy the file to your Assets (or any folder inside it) of your main project, load it into your main in the Edit > Project Settings > Graphics and Shader Preloading area.

    I'm making this post because I couldn't find any Unity Tutorial about this and if your project has a similar pipeline to mine, maybe it could help! But if this post is in any way inapropriate, I'll remove it.

    Thanks a lot!
     
  2. abennani

    abennani

    Joined:
    Mar 20, 2019
    Posts:
    1
    Thank you so much! you saved my android project!

    I am using .gcinc shaders and trying to export them to assetbundle, it works fine on iOS but in Android .gcinc was not included in dependencies.

    I tried this and it works great. I confirm that it also works when the shaders are defined under "Always included Shaders" but it takes a lot more size!
     
    iseta likes this.
  3. iseta

    iseta

    Joined:
    May 5, 2016
    Posts:
    48
    Whew, I'm glad I could help someone, it was quite a headache on the specific project where this problem came up! :D

    And yes, this was kind of a workaround for "Always Included Shaders" since they do tend to take up a lot of space, specially the Standard ones.
     
    ssunil likes this.
  4. ssunil

    ssunil

    Joined:
    Apr 6, 2020
    Posts:
    1
    Thanks a Lot That is gonna save a heck lot of time
    really thank you
     
  5. jamespaterson

    jamespaterson

    Joined:
    Jun 19, 2018
    Posts:
    400
    iseta likes this.
  6. PrathU2218

    PrathU2218

    Joined:
    Dec 18, 2020
    Posts:
    2
    Hey! thanks for this great suggestion, I was searching for this from 3 days, but I am getting another error so I just to ask you if you also got this error, so maybe you can help me out,

    This is the error I am getting:
    Assertion failed on expression: 'm_UserPathRemap.count(pathStr) == 0' UnityEditor.BuildPipeline:BuildAssetBundles (string,UnityEditor.BuildAssetBundleOptions,UnityEditor.BuildTarget) CreateAssetBundles:BuildAllAssetBundles ()

    Thanks in advance
     
  7. iseta

    iseta

    Joined:
    May 5, 2016
    Posts:
    48
    Hey! This might be a bug related to your Unity Version, I've seen this error reported on a few other threads, there's few solutions mostly related to upgrading the project, so this seems like the general fix, which version are you using?

    Also, the threads in question: https://forum.unity.com/threads/ass...on-gondemandassets-empty.837835/#post-5910488
    https://forum.unity.com/threads/assertion-failed-on-expression-error-on-saving-scene.834244/
    https://forum.unity.com/threads/assertion-failed-on-expression-ins-second-ins-first-second.955254/
     
  8. chgeorgiadis

    chgeorgiadis

    Joined:
    Jan 30, 2018
    Posts:
    51
    Thank you for the perfect solution!
    I have a question. A have an avatar made from Character Creator 3. After i imported to Unity i have to make some changes on shaders because there is a bad result on default version. When i complete the changes i make the asset bundle but when i call it, the avatar comes with the first shaders (photos below) How can i fix that? Maybe the problem is that i have the same names on shaders?

    prefab.JPG bundle_shaders.JPG
     
  9. JamesT0ngue

    JamesT0ngue

    Joined:
    Jun 24, 2018
    Posts:
    3
    You juste save my project that's insane, thank you so much !
    I'm working on my Augmented Reality app' too, and I've the same 150mb playstore problem so you're just the best aha
     
  10. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    Here's some facts about shaders, materials and asset bundles that might help people in the future (also applicable to addressables, which is just an asset bundle manager):

    Shader variants controlled by shader_feature keywords are only included in builds when Unity detects they are used by a Material or ShaderVariantCollection. For example, if no material uses the "cutout" keyword, no variants including that keyword will be built.

    When Unity builds an asset bundle, it basically builds a resource file with only the assets (or scene) assigned to that bundle and all other assets are completely ignored (in addressables, a bundle is generated for each group which is set to "pack together" or for each asset in a group if it's set to "pack separately"). Those assets' dependencies will also be included in the bundle, but only if they aren't assigned to their own asset bundle. If they are assigned to a different bundle, the name of that bundle will be added to the list of "asset bundle dependencies" of the bundle being built. You then need to make sure to load the dependencies' bundle(s) before loading the main bundle, otherwise those assets will be missing (addressables loads/unloads dependencies automatically).

    Now to the two biggest issues that can happen when those things are combined:

    1) You assigned bundles to your materials, but didn't assign bundles to your shaders:
    Since bundles are built in complete isolation, Unity will include a copy of the shader to each bundle that depends on it. Also, each bundle will contain only the variants used by the materials in it. For example, if bundle A contains materials that use "cutout" and bundle B only contains materials that don't, the cutout variants will exist only in A and not in B. This can greatly increase memory usage and loading stutters if you have a game that constantly loads prefabs from bundles (for example, by having every piece of equipment be in its own bundle).
    Solution: Make sure your shaders are assigned to bundles or addressable groups.

    2) You assigned bundles to your materials and shaders, but the shaders and materials are not in the same bundle:
    Since the shaders' bundle doesn't contain any materials, Unity won't know what shader_feature keywords it really needs to include. This will result in materials missing features like different blend modes, normal maps and so on.
    Solution: Make sure your shaders are in the same bundle as the materials or ShaderVariantCollections which reference them.

    The best solution is to generate one or more ShaderVariantCollection assets with all keywords you do use then place it and the shaders they use in a single asset bundle. This eliminates shader duplication (shaders will be in an explicit bundle) and missing features (the variant collection will tell Unity which variants it needs), while giving you freedom to put your materials in whatever bundles/groups you need.

    Also, for those using the built-in render pipeline and not using addressables (managing bundles themselves): when using the "legacy" build pipeline you cannot assign Unity's built-in shaders to asset bundles. The legacy build pipeline assigns bundles to asset paths and the built-in assets don't have proper asset paths. You need to either :

    1) Download and copy all built-in shaders to your project (and change all materials to use the copies instead)
    2) Refactor your asset bundle building scripts to use the Scriptable Build Pipeline package (or the low level Unity functions that package uses) instead.

    The scriptable build pipeline allows assigning asset bundles to asset GUID + fileId, which makes it possible to assign Unity's built-in assets to asset bundles (shaders, default textures, and even the built-in shapes). It even allows you to assign specific sub-assets to bundles.