Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by Kabutak · Nov 22, 2016 at 09:05 AM · c#renderingshadersmaterials

Instanced material ignoring value changes.

So, I'm working with some objects in my scene that use dynamic materials which are modified at runtime. However, in an attempt to clean up the code some, things have stopped working. I used to instantiate the materials as needed, modify them and set them. That worked fine, but without proper garbage collection that leads to a reasonable memory leak.

Logically speaking, I should only have to instantiate the material once per object, and modify the instance from there. However, all of my attempts to do this lead to Unity simply ignoring any changes at runtime. I have even debugged the values as they change, and they are changing within the material, there is just no visible change. If I modify the values at start, regardless of order, they work. After start, however, anything I do is ignored unless I instantiate another copy, which should not be the case.

     void Start()
     {
         //This works
         Material mat = Instantiate(PosterImage.material);
         mat.SetFloat("_EffectAmount", 0f);
         PosterImage.material = mat;
 
         //This also works
         PosterImage.material = Instantiate(PosterImage.material);
         PosterImage.material.SetFloat("_EffectAmount", 0f);
     }

Any combination of setting the value and the material in any order within start works perfectly, but if I try to modify that in any way afterwards, it sets the value and does not change anything physically in scene. I would try MaterialPropertyBlocks, but the objects do not have a renderer as they are canvas based. Worst case scenario I will have to go back to instantiating and manually cleaning up the materials, but that is really not something that should be necessary. Is there something I am missing, or is this a limitation of Unity.

Edit: I suppose it helps to mention that the PosterImage variable is an Image, from UnityEngine.UI, so it is governed by a CanvasRenderer as opposed to the standard renderer, as stated above.

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Adam-Mechtley · Nov 22, 2016 at 09:29 AM 0
Share

Can you post an example of code that does not work?

avatar image Kabutak Adam-Mechtley · Nov 22, 2016 at 03:11 PM 0
Share

If I have instantiated it beforehand, any combination of references and resetting do not work, even though the references are updating.

      void UpdateTexture()
      {
          //This works
          $$anonymous$$aterial mat = Instantiate(PosterImage.material);
          mat.SetFloat("_EffectAmount", 0f);
          PosterImage.material = mat;
  
          //This does not work
          PosterImage.material.SetFloat("_EffectAmount", 0f);
 
          //Neither does this, assu$$anonymous$$g I store the instance at the start
          $$anonymous$$atInst.SetFloat("_EffectAmount", 1f);
          PosterImage.material = $$anonymous$$atInst;
 
          //If I debug the value after modifying it, the value HAS changed
          //However, it does not change how things are rendered at all
          //Unless I re-instantiate and re-set the material
          Debug.Log(PosterImage.material.GetFloat("_EffectAmount"));
 
          //This is the only way currently to make it work cleanly
          $$anonymous$$aterial mat = Instantiate(PosterImage.material);
          Destroy(PosterImage.material);
          mat.SetFloat("_EffectAmount", 1f);
          PosterImage.material = mat;
      }

2 Replies

· Add your reply
  • Sort: 
avatar image
3
Best Answer

Answer by Adam-Mechtley · Nov 22, 2016 at 08:45 PM

Have you tried setting the float on the materialForRendering property instead of the material property?

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kabutak · Nov 22, 2016 at 10:36 PM 0
Share

So, upon testing that appears to work just fine, without any memory leaking. The odd part is that according to the docs: "By default it's the same as Graphic.material" so it should really have already been working. What is the purpose of the material value if Unity decides to render a different material? Oh well, that's a mystery for another day. Thanks.

avatar image Adam-Mechtley Kabutak · Nov 22, 2016 at 10:55 PM 0
Share

If you have any I$$anonymous$$aterial$$anonymous$$odifier objects (e.g., $$anonymous$$asks) acting on the component, then the material actually submitted to the renderer may not be the same as the default one specified.

avatar image Kabutak Adam-Mechtley · Nov 23, 2016 at 05:03 PM 0
Share

It should also be noted that while using this method, you still need to instantiate the material at start, or else they will continue to edit the base material. This may not always be an issue, but it is far from ideal, so save yourselves the headaches and instance those materials in advance.

avatar image
0

Answer by Bunny83 · Nov 22, 2016 at 06:04 PM

I don't quite get your problem. Whenever you acutally use renderer.material, Unity will automatically create an instance of the original material just for this object. Unity does this "once" for each object. There's no need to instantiate the material manually. If you want to access the shared material (which doesn't auto-instantiate the material on access) you have to use "sharedMaterial".

If the value in the material has actually changed but doesn't affect the actual object, make sure the object is not marked as static because chances are high that the object has been statically batched. Batching in general could be a problem here.

What exactly is "PosterImage"?

ps: Materials are not automatically garbage collected when you loose all references to it. All objects derived from UnityEngine.Object can be recovered by using FindObjectsOfType. They are automatically removed when you change the scene or when you call Resources.UnloadUnusedAssets.

So when you no longer need a dynamically created Material you should Destroy it.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kabutak · Nov 22, 2016 at 07:29 PM 0
Share

PosterImage is an Image object, from UnityEngine.UI. It is therefore governed by a CanvasRenderer. I am aware that the materials are not garbage collected, so I've got to destroy them on my own as I go to avoid needing Resources.UnloadUnusedAssets. I've not marked any of the objects in question as static, since they are dynamically generated and modified at runtime.

avatar image Bunny83 Kabutak · Nov 23, 2016 at 02:46 PM 0
Share

Well, that turns the question into something completely different ^^. $$anonymous$$ost things that are rendered in Unity use some sort of renderer. However the new UI system works a bit different.

Good that your comment / question update lead $$anonymous$$to properly answer your question ^^.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

7 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Blend 2 linerender colors at point of interception 0 Answers

Limiting player view dependent on position and obstacles 0 Answers

Custom Shader with Canvas Renderer limit draw calls. 0 Answers

How do i change the Alphasorting Center to the Pivot in Meshrenderers? 0 Answers

What's the difference between using "[PerRendererData]" and "Enable GPU Instancing" in Unity shaders/materials? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges