Search Unity

Bug Emissive Textures generated at runtime don't apply unless inspected

Discussion in 'High Definition Render Pipeline' started by UserAnon91, Mar 7, 2021.

  1. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    Hey Team,

    I've happened across something breaking to my project with regards to both URP and HDRP.

    A quick summary of my process;

    Bullets travel in a level, causing a glowing light. Rather than using lights since there may be over 3 000 bullets, i'm opting to build a texture, and use the emissive property of the grid.

    Generating the texture at runtime, either in Start, Awake or Update is successful, and applies to the material correctly, but won't be reflected in the Game or Scene views, unless the material is unfurled in the inspector.

    This seems to only able to be rendered by inspecting the material, and the same issue happens in Standalone builds, leading to the texture never being rendered (since there's no inspector)

    I've attempted recalculating the DynamicGI, and requested the renderer update its GI materials, all to no avail.

    I've reproduced this in a contained environment on Unity 2019.4.13f1 (LTS) here; https://github.com/UserAnon91/UnityEmissionBug

    This bug is still present on the newest version of unity, with the latest version of HDRP

    A demonstration of the perceived bug is here;


    The code used to reproduce is simplified here;

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class EmissionBugReproduce : MonoBehaviour
    6. {
    7.     public Material newNewGridMaterial;
    8.  
    9.     public Texture2D gridTexture;
    10.     public Renderer ourRenderer;
    11.  
    12.     // I've originally split this into awake or start,
    13.     // then update the texture every 0.1 seconds with the same result
    14.     void Awake()
    15.     {
    16.         gridTexture = new Texture2D(100, 100);
    17.  
    18.         for (int i = 0; i < 100; i++)
    19.         {
    20.             for (int j = 0; j < 100; j++)
    21.             {
    22.                 if (i % 2 == 0 && j % 2 == 0)
    23.                 {
    24.                     gridTexture.SetPixel(i, j, Color.magenta);
    25.                 }
    26.                 else
    27.                 {
    28.                     gridTexture.SetPixel(i, j, Color.black);
    29.                 }
    30.             }
    31.         }
    32.         gridTexture.filterMode = FilterMode.Point;
    33.  
    34.         gridTexture.Apply();
    35.  
    36.         ourRenderer.material.SetTexture("_EmissiveColorMap", gridTexture);
    37.  
    38.         /*******************************/
    39.  
    40.         /*
    41.         Additionally, i've attempted to use:
    42.  
    43.         newNewGridMaterial.EnableKeyword("_EMISSION");
    44.         newNewGridMaterial.EnableKeyword("_Emission");
    45.         newNewGridMaterial.EnableKeyword("_Emissive");
    46.         newNewGridMaterial.SetTexture("_BaseColorMap", gridTexture);
    47.  
    48.         ourRenderer.material = newNewGridMaterial;
    49.  
    50.         DynamicGI.SetEmissive(ourRenderer, Color.white);
    51.         ourRenderer.UpdateGIMaterials();
    52.         */
    53.     }
    54. }
     
    theRTC likes this.
  2. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    Hopefully I can get a workaround or fix for this as it's breaking my builds. Does anyone have suggestions on how to fix this temporarily?
     
  3. M4dR0b

    M4dR0b

    Joined:
    Feb 1, 2019
    Posts:
    108
    Y-Hello there,

    [Edit] Forgot to ask. Did you try to build the prj? Does it wield the same result?

    I've tried your script, yes there's a weird bug but can be fixed with a workaround which is actually better for this case scenario.

    instead of:

    Code (CSharp):
    1. ourRenderer.material.SetTexture("_EmissiveColorMap", gridTexture);
    you can try:

    Code (CSharp):
    1. ourRenderer.sharedMaterial.SetTexture("_EmissiveColorMap", gridTexture);
    the first is actually creating an instance of the material you are referencing, while the latter is using the actual material you set up.

    Idk if that's the final code, but I wouldn't create that texture at runtime, just save it and use it.
     
    Last edited: May 4, 2021
    UserAnon91 likes this.
  4. chap-unity

    chap-unity

    Unity Technologies

    Joined:
    Nov 4, 2019
    Posts:
    766
    Hey @UserAnon91, I have logged something as it's indeed surprising that we need to inspect the material for it to be updated in game view. I will update here once we have more info on this.

    In the meantime, don't forget to set your "_EmissiveColor" property to white (it's black by default), otherwise, even with the sharedMaterial workaround, your emissive won't show.
     
    UserAnon91 and M4dR0b like this.
  5. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    ok! so i changed it to sharedMaterial and it's looking like it's only working in editor when you have the material on the object inspected/uncollapsed.

    from the inspector standpoint, making the new instanced material using material.setTexture was collapsing the menu, which had me need to click on the material, but since it's the same material with sharedMaterial.setTexture, it doesn't collapse that menu and is always inspected. So by proxy, this is in fact helping, but i need to have the object the material is assigned to inspected and its material panel opened at all times. This is much closer, but still won't work when the project is built and run.

    The code snippet i put here in the original post is a very slimmed-down version of my go-live code for the sake of reproduction, there are reasons i need to edit the texture every n-frames for the sake of game logic, but I don't need to recreate it every frame, you're correct.

    I've uploded a revised version of the bug here;



    As for your post @chap-unity , thank you for making a report on it! My emission is set to white on the material at all times,
    upload_2021-5-4_12-48-46.png

    Is there anything else that you can think of that might help remediate this issue in the meantime? Progress can technically continue on the project while this bug is affecting me, i'll need to have an inspector panel locked to have this material showing at all times, but builds aren't able to contain this core feature i'm working on, which is a shame.

    Let me know and thank you for your help so far!
     
  6. M4dR0b

    M4dR0b

    Joined:
    Feb 1, 2019
    Posts:
    108
    @UserAnon91 sorry to read that, I didn't test it properly.

    This is a weird looking bug, good finding, worth of a bug report if there's none.

    Anyhow, I've tried also with MaterialPropertyBlock workaround with no success.
    The only things that seems to work is to pre-assign a base emissive texture (it could be a white 1x1 px) and than assigning the grid one at runtime, I've tested this and it does work in Editor and in Build.

    Hopefully is a workaround that works for you until a fix is found.
     
    UserAnon91 likes this.
  7. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    WOW, Legend!

    So this actually works for me now, with a few notes:

    I've created a 1x1 #FFFFFF pixel and assigned it to the emission colour texture channel in-editor.

    With sharedMaterial, it overwrites this channel, and on stopping play leaves that channel empty because the texture i created no longer exists.

    I switched back to material from sharedMaterial, and with the 1x1 white pixel texture in the emission channel, it will load it every time, both inspected, not inspected, and even in builds!

    A very strange issue, and the bug still very much exists, but putting a texture inside that channel before runtime seems to be the fix, and as far as workarounds go, pretty mild!

    Thank you so very much for your help @M4dR0b , that's a great in-the-meantime fix for what i'm trying to do :)

    EmissiveTextureResult.gif
     
  8. M4dR0b

    M4dR0b

    Joined:
    Feb 1, 2019
    Posts:
    108
    Glad that worked out for you.

    That luminous grid is looking dope, are you doing that with unity internal lights or you built your own?
     
    Last edited: May 5, 2021
    UserAnon91 likes this.
  9. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    I'm not using any lights in the scene at all, it's all emissive using a texture that i update every N seconds. The base is a transparent grid that emits white, then i emit my custom coloured texture via the emission albedo texture.

    Each square is recorded by the GameManager and used by the GridCreator to generate a radius per-cube based off its colour.

    I bred this from a need to not have several thousand lights i a scene for a bullet hell i've been working on. This is much more performant, as you can imagine.
     
    M4dR0b likes this.
  10. chap-unity

    chap-unity

    Unity Technologies

    Joined:
    Nov 4, 2019
    Posts:
    766
    Got more info on this one !

    In the end, there's no issue, if you want to modify a material property at runtime you need to make sure the feature is enabled in the shader you're using.
    If it's not the case before runtime (like for example not having a emissive texture) the specific variant won't be included and you won't be able to modify it in play mode. (and won't be included in your unity player as well)

    To include the variant, you need to enable the specific keywords that triggers it;
    You can find the list by right clicking on the Lit Shader and click edit shader, there you'll find the list of keywords after #pragma prefixes.

    In your case it's "_EMISSIVE_COLOR_MAP", and puting this line before editing the "_EmissiveColorMap" field fixes the issue.

    Code (CSharp):
    1. this.GetComponent<Renderer>().material.EnableKeyword("_EMISSIVE_COLOR_MAP");
    upload_2021-5-26_10-34-39.png
     
    M4dR0b likes this.
  11. M4dR0b

    M4dR0b

    Joined:
    Feb 1, 2019
    Posts:
    108
    oooooh, that is good to know for future reference.

    Thanks @chap-unity
     
  12. chap-unity

    chap-unity

    Unity Technologies

    Joined:
    Nov 4, 2019
    Posts:
    766
    Yep, we'll try to include those bit of information in the documentation actually.
    It can be useful to some since material edition at runtime is quite common !