I am working on optimising a game I’m working on and noticed in the docs that using shader property Id’s rather than their names would be more efficient.
The docs do not give much detail about the performance boost and I was unable find any more info. I therefore decided to create a thread here in hopes of someone being able to shed some light for me and others interested.
What I’m currently interesting about is:
Why using the ID’s is more efficient? What is happening behind the scenes?
What approach are people using for storing numerous property ID’s? Would it be wise to create and populate a Dictionary<string, int> at the start of the game and then use that to retrieve and use the ID’s?
A dictionary is likely similar to the internal resprentation of what Shader.PropertyToID() is. The cost of calling that function is a combination of the cost of crossing between the c# and native code, and the internal dictionary lookup.
What we’d done on our projects is either have each class store them like my example above, or have a ShaderParams class which exists solely to be the holder of the IDs mapped to public variables.
Thank you for the explanation.
Good to know what’s happening underneath the hood (Note to the Unity peeps: Maybe add this info to the docs?)
I was afraid of that the dictionary approach would not be a good one. I just wanted to avoid making my ShaderParams class blow up in size since I want the data contained in to one class rather than having each class to store the ID’s.
Coming back to this, we just had a file setup like this:
public class ShaderParam {
public static int color = Shader.PropertyToID("_Color");
public static int alpha = Shader.PropertyToID("_Alpha");
}
It was a single file called HashCache.cs with a bunch of these method-less classes just full of public static variables. In your script where you actually use the Set___() functions you do this:
The main reason why you should use PropertyToID() instead of calling strings every time was explained in this video:
Basically, whenever you use an int, a string or any kind of stored parameters, Unity generate a new block in its memory to hold onto that information. Every single time unless it’s one that was already used (same gameobject ID). So, if you have a script that manage something multiple time the same way, but for different instances in any scene, each time generate a new block to hold onto the information. Even if you close the scene, the block doesn’t get removed, but is only cleaned from its content. While minimalist in terms of how much memory is kept for all those “empty” blocks that might remains unused, if you consider that each block might hold onto like as much as 256 bits just to exist (even if it’s empty), if you got many thousands of those existing in the engine after an app/game has run through a couple of scenes or events or whatever, it can be considered like a small tiny kind of memory leak issue.
So, by using PropertyToID() in a public static class and by only using that, you’re saving 1 block every time you need to use that particular property. Same if you’re using something like for(int a = 0; a < List.lenght (or Array.count); a++) kind of marker as the .length and .count generate a new block unless you use a bunch of permanent reusable integer especially for those kind of things. (In my case, I usually keep 3 public static int KeepTrack_A {get; set;} in my game’s systems (which are set as Dont Destroy) and I use those every time I have to do a for(). I keep 3 of those since, some times, I have to do 1 within another (so 2 levels) or some other time, I’m uncertain if one is still being used while another might already be used or something like that).