Search Unity

Fade one object with a shared material?

Discussion in 'Scripting' started by Ramen Sama, Apr 10, 2010.

  1. Ramen Sama

    Ramen Sama

    Joined:
    Mar 28, 2009
    Posts:
    561
    For starters, I do know how to how to adjust the alpha for materials. But...

    How can you fade one object but not another using the same material?

    I want to setup objects like pillars that will become transparent when blocked by the camera view, but i don't want every pillar in the scene to become transparent.

    I'm thinking i'll need to do something like dynamically create a material just for the pillar in question.

    Any ideas?
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    That's not possible...the color is a property of a material, so altering the color alters everything that uses that material.

    Actually Unity does that automatically for you. If you say "renderer.material.color.a = .5", then Unity makes a copy of the material in the scene, and only the copy has an alpha of .5. The downside is that you no longer have shared materials (which is a problem on Unity iPhone because no shared material = no batching). Also you don't have a reference to the copy of the material, so it's not so easy to destroy it later. Therefore dynamically creating a material yourself is sometimes a good idea.

    --Eric
     
  3. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    An alternative is to programmatically script the vertex colors' alpha channel. Then you can use the same material for every pillar. However, if you're going to have most of your pillars not be transparent, then it's probably best to just dynamically assign the transparent material when appropriate. Using a transparent material on everything will likely drop your framerate, even if its alpha is one (I haven't bothered to test this myself, really,).
     
  4. Ramen Sama

    Ramen Sama

    Joined:
    Mar 28, 2009
    Posts:
    561
    Alright, so i suppose my workflow should be to make a make a new transparent material and populate it's data using the current material so i can modify the alpha, then when fading is no longer needed, reassign the old material and delete the temporary one. I'll give it a shot and post some code if it works. And also if it doesn't.


    @ Jessy

    I used the idea of a pillar as an example. Ideally, i'd want any object that gets in the view of the camera able to be transparent. But i don't plan on have too many objects get in front of the camera, personally i hate it when cameras "correct" themselves by moving closer to the character.

    As my project is a 3rd person game with a movable camera, i'd like to avoid a camera that has a mind of it's own.

    Plus this could be useful for other things like fading objects in or out while creating/deleting.
     
  5. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    http://docs.unity3d.ru/ScriptReference/Material.CopyPropertiesFromMaterial.html

    I wouldn't do it this way, I'd just keep the two types of materials in an array or class, and then switch the renderer's material on the fly. Faster, and avoids garbage collection.
     
  6. Antitheory

    Antitheory

    Joined:
    Nov 14, 2010
    Posts:
    549
    If anyone is still interested in this topic I have written a class to manage alternate materials. In my case I am using it to highlight collectable objects... It doesn't switch the swap the material for a different one, (which would actually be more useful in the op's case), it just makes the sharedMaterial a single-user copy so you can edit it as you see fit... when you are done you can reset it back to the original sharedMaterial so you can still benefit from batching. The script also reuses the previously created materials for faster swapping.

    As I said above I am using it to highlight objects which are collectable by my character when the mouse is over them.

    I have only just made this and tested it right now... It's working for me but I can't guarantee that it's 100% bug-free.

    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MaterialSwap
    6. {
    7.     static private Dictionary<Material, List<Renderer>> sharedMaterials = new Dictionary<Material, List<Renderer>>();
    8.     static private Dictionary<Renderer, Material> renderers = new Dictionary<Renderer, Material>();
    9.     static private Dictionary<Material, List<Material>> alternates = new Dictionary<Material, List<Material>>();
    10.     static public int maximumUnusedAlternates = 5;
    11.     static public void AddMaterial(Renderer renderer)
    12.     {
    13.         Material material = renderer.sharedMaterial;
    14.         if (renderers.ContainsKey(renderer))
    15.         {
    16.             Debug.LogWarning("The dictionary already contains the renderer for " + renderer.name);
    17.             return;
    18.         }
    19.         else
    20.             renderers.Add(renderer, material);
    21.  
    22.         if (sharedMaterials.ContainsKey(material))
    23.         {
    24.             if (!sharedMaterials[material].Contains(renderer))
    25.                 sharedMaterials[material].Add(renderer);
    26.         }
    27.         else
    28.             sharedMaterials.Add(material, new List<Renderer> { renderer });
    29.            
    30.     }
    31.  
    32.     static public Material ResetMaterial(Renderer renderer)
    33.     {
    34.         if (!renderers.ContainsKey(renderer))
    35.             Debug.LogWarning("The dictionary does not contain the renderer for " + renderer.name);
    36.         else
    37.             renderer.sharedMaterial = renderers[renderer];
    38.  
    39.         return renderer.sharedMaterial;
    40.     }
    41.  
    42.     static public Material SetAlternateMaterial(Renderer renderer)
    43.     {
    44.         Material material = renderer.sharedMaterial;
    45.  
    46.         if (!sharedMaterials.ContainsKey(material))
    47.         {
    48.             if (renderers.ContainsKey(renderer)) {
    49.                 Debug.LogWarning(renderer.name + " is already using an alternate material!");
    50.                 return material;
    51.             } else {
    52.                 Debug.LogWarning(renderer.name + " has not been added to the dictionary... adding now.");
    53.                 AddMaterial(renderer);
    54.             }
    55.         }
    56.         List<Material> mList;
    57.         if (alternates.ContainsKey(material))
    58.         {
    59.             Debug.Log(alternates[material].Count + " alternates for material " + material.name);
    60.             mList = new List<Material>(alternates[material]);
    61.  
    62.             foreach (Renderer r in sharedMaterials[material])
    63.                 if (r.sharedMaterial != material)
    64.                     mList.Remove(r.sharedMaterial);
    65.  
    66.             if (mList.Count == 0)
    67.             {
    68.                 mList.Add(renderer.material);
    69.                 alternates[material].Add(mList[0]);
    70.             }
    71.             else
    72.             {
    73.                 if (mList.Count > maximumUnusedAlternates)
    74.                     for (int i = 1; i < mList.Count; i++)
    75.                     {
    76.                         alternates[material].Remove(mList[i]);
    77.                         GameObject.Destroy(mList[i]);
    78.                     }
    79.  
    80.                 mList[0].CopyPropertiesFromMaterial(material);
    81.             }
    82.         }
    83.         else
    84.         {
    85.             mList = new List<Material> { renderer.material };
    86.             alternates.Add(material, mList);
    87.         }
    88.         renderer.sharedMaterial = mList[0];
    89.         return renderer.sharedMaterial;
    90.     }
    91. }
    92.  
     
    Last edited: Apr 29, 2011
  7. Kyu

    Kyu

    Joined:
    Jul 27, 2012
    Posts:
    4
    This thread is from 2010, but it's the first hit on google, so based on Jessy's tip, here's the code that worked for me and does not break batching:

    Code (csharp):
    1.  
    2. private void Awake () {
    3.     this.mesh = this.gameObject.GetComponent<MeshFilter>().mesh;
    4. }
    5.  
    6. protected void SetOpacity (float opacity) {
    7.     Color[] colors = this.mesh.colors;
    8.  
    9.     for (int i = 0 ; i < this.mesh.vertexCount; ++i) {
    10.         colors[i].a = opacity;
    11.     }
    12.        
    13.     this.mesh.colors = colors;
    14. }
    15.  
    16.  
    Cheers