Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Detail Maps and Asset Bundles

Discussion in 'High Definition Render Pipeline' started by mmkc, Aug 3, 2021.

  1. mmkc

    mmkc

    Joined:
    Sep 12, 2019
    Posts:
    49
    I'm trying to set a Detail Map on a gameobject and material that are loaded from an asset bundle. I enable the material's "_DETAIL_MAP" keyword and set the texture, but it doesn't have any effect. If I uncomment out the first line, it works just fine. The material that comes in the asset bundle has all defaults.

    Code (CSharp):
    1.                 //gameObject.GetComponent<MeshRenderer>().material = new Material(Shader.Find("HDRP/Lit"));
    2.                 Material material = gameObject.GetComponent<MeshRenderer>().material;
    3.                 material.EnableKeyword("_DETAIL_MAP");
    4.                 material.SetTexture("_DetailMap", texture);
    I will try to reproduce this in an isolated project, but before I do, does it seem like there is anything obviously wrong with what I'm doing here?
     
  2. mmkc

    mmkc

    Joined:
    Sep 12, 2019
    Posts:
    49
    I've attached a very small project that reproduces the issue. It comes with an asset bundle that was built in the same project. If you load the asset bundle and try to set the detail map on the gameobject inside the scene, it doesn't work. If you just load the scene (not from the asset bundle) and apply the detail map, it works just fine.
     

    Attached Files:

  3. BOXOPHOBIC

    BOXOPHOBIC

    Joined:
    Jul 17, 2015
    Posts:
    523
    Hi, try getting the shared material instead. When you get the .material, unity will create an instance, so you don't modify the actual material:

    Code (CSharp):
    1. Material material = gameObject.GetComponent<MeshRenderer>().sharedMaterial;
    If you want to modify that particular instance, I think you need to reassign the material

    Code (CSharp):
    1. Material material = gameObject.GetComponent<MeshRenderer>().material;
    2. material.EnableKeyword("_DETAIL_MAP");
    3. material.SetTexture("_DetailMap", texture);
    4.  
    5. gameObject.GetComponent<MeshRenderer>().material = material;
     
    Last edited: Aug 5, 2021
  4. mmkc

    mmkc

    Joined:
    Sep 12, 2019
    Posts:
    49
    I appreciate the reply. Using sharedMaterial doesn't seem to work in this case either, and neither does reassigning the material back to the MeshRenderer. Besides, keeping my code as is but just replacing "_DetailMap" with "_BaseColorMap" correctly sets the Base Map.
     
    BOXOPHOBIC likes this.
  5. Remy_Unity

    Remy_Unity

    Unity Technologies

    Joined:
    Oct 3, 2017
    Posts:
    707
    Hi @mmkc
    I'm investigating on this issue, and I may think this is an expected behavior :
    I also tried reproducing the issue with built-in shaders and materials, and it the same there. I suspect that when you bundle a material in an asset bundle it get there with it's shader and lives on its own. When you add the detail map keyword to the shader, in will not just set a toggle, it actually asks to use an other variant of the shader, an other code, that doesn't exist in the assetbundle.
    I tried manually creating a material with the detail map and adding it to the assetbundle so the needed shader variant is already there when the code is executed, and it worked.
    The fact that it works when you uncommented the line where you create a new material is probably because when you do this, you're not relying anymore on the shader embeded in the bundle.


    This is because the "base" shader variant already deals with this map, and doesn't need any additional keyword.

    I will investigate further and ping around internally to be sure, but like mentioned, I think it is expected and you have to bundle all the needed shader variants that you intend to use.
     
  6. mmkc

    mmkc

    Joined:
    Sep 12, 2019
    Posts:
    49
    Hmm OK so would it be safest to enable the detail map keyword on all materials before building the asset bundles?
     
  7. Remy_Unity

    Remy_Unity

    Unity Technologies

    Joined:
    Oct 3, 2017
    Posts:
    707
    Not really, as if you have the detail map keyword enabled, then the shader variant without it might be missing. Like I mentioned, add in your asset bundle at least one material with the detail map keyword enabled.
     
  8. mmkc

    mmkc

    Joined:
    Sep 12, 2019
    Posts:
    49
    OK thank you. One question though... we have an asset bundle that contains many of the common shaders used by our many asset bundles, and build those asset bundles with this common bundle as a dependency. Can I just update the common one and it will try to look for it there?
     
  9. mmkc

    mmkc

    Joined:
    Sep 12, 2019
    Posts:
    49
    Also, could I just add the correct combination of keywords to the shader variant collection that's in that asset bundle?
     
  10. mmkc

    mmkc

    Joined:
    Sep 12, 2019
    Posts:
    49
    One more question (sorry)... what other keywords would this apply to or how can I determine that? Normal maps? Height maps? Mask maps?
     
  11. Remy_Unity

    Remy_Unity

    Unity Technologies

    Joined:
    Oct 3, 2017
    Posts:
    707
    I'm not very used to how assetbundles work, but I found a better solution to your issues. Instead of creating a lot of materials, use a ShaderVariantCollection asset. Insert all the variants you need there and add the asset to your assetbundle.
    Note that single keywords is not enough, a variant is a combinations of keywords.
    If you inspect a HDRP/Lit material with the detail map you want to use in your attached project with the inspector in debug mode, it will have the following keywords :
    _DETAIL_MAP _NORMALMAP _NORMALMAP_TANGENT_SPACE

    So using only the
    _DETAIL_MAP
    one is not enough.
    We do have an editor function that fixes the material keywords depending on what is set up, but it won't help with missing variants, and obviously, won't work in a build :
    UnityEditor.Rendering.HighDefinition.HDShaderUtils.ResetMaterialKeywords(material)


    So, to make your attached project work you need to :
    - add a ShaderVarianCollection asset with the HDRP/Lit shader and the above mentioned keywords combo as variant
    - add this asset to the assetbundle, and rebuild it
    - change the script so properly enable all the needed keywords on the material :
    Code (CSharp):
    1. material.EnableKeyword("_DETAIL_MAP");
    2. material.EnableKeyword("_NORMALMAP");
    3. material.EnableKeyword("_NORMALMAP_TANGENT_SPACE");
    I tried this locally and it worked. And like mentioned, you need to list all the variants that you need in the asset. You can use the API to automatically add variants, but there is not way that I know of to automatically find which ones you'll need.