• Unity
  • Best way to change materials for characters in object pool!

  • تم التحرير
Related Discussions
...

Hey y'all!

I'm trying to change material properties per individual character in my object pool in Unity, and I want to do it as soon as my game loads up and dynamically sets it all up. So far I have scoured the forums and haven't found a means that fits what I need, but at the moment, I feel like my best bet is somehow duplicating the skeleton & modifying it's material properties deep within the atlasasset (specifically a fresh, new material instance).

Any insights on this?

Using Unity 4.6.3 and Unity 5.1 for this (two separate approaches).

yep... this process pretty much sucks now.

ideally we'd be able to provide an alternative AtlasAsset to load from rather than just the one specified in the AtlasAssets array of the SkeletonDataAsset. No code exists in the runtimes to let you do that though. Ultimately what I think will happen is a delegate function will need to be created that says "GetAtlasAssets()" and you can override that when you want to when initializing a new skeleton.

Hacky quick solution: probably best I just hand-create the 150 specific objects in my pool for now? 🙂

Can't you just use Renderer.GetPropertyBlock and Renderer.SetPropertyBlock on a per skeleton basis. I think it is meant to support not breaking dynamic batching but I can't be sure, it should work for different float, color or vector properties. If you set that though then you could modify the material properties without duplicate instances. You could then just modify propertyblock per skeleton with a script, or write some .txt, .json or .whatever file that you parse that contains info for each skeleton, and then instantiate the skeletons and change their property blocks based on that info, either within the Unity editor or at runtime... At least that way you would only have to maintain a text file or excel file (export to csv) for 150 different combinations.
Just throwing some ideas out there, hope it helps 🙂

Nope, Spine will redraw it each frame as the original material set in the AtlasAsset. 🙂

If I could do what ya' suggested, I could easily just loop through my 150 pooled objects to adjust that single material property to build what I need very quickly. In fact that's what I initially did.

Look around Line 208 to 216 in SkeletonRenderer.cs to see where I found my problem. As Mitch said, its looking like it'll be a rough one to do what I want.

My skeletonRenderer is heavily modified so I'm not so sure about line numbers...

But if you are referring to the place where the sharedMaterials are overwritten, then it is possible.
If you had a shader property "someColor" for example, then to change it for lots of different skeletons you could just do the following; (this is bad though, don't actually do it like this, cache propertyBlocks, don't create a new one each frame)

// Set materials.
        if (submeshMaterials.Count == sharedMaterials.Length)
            submeshMaterials.CopyTo(sharedMaterials);
        else
            sharedMaterials = submeshMaterials.ToArray();
        GetComponent<Renderer>().sharedMaterials = sharedMaterials;

// New stuff 

---


    MaterialPropertyBlock block = new MaterialPropertyBlock();
    GetComponent<Renderer>().GetPropertyBlock(block);
    block.SetColor("_someColor", someColor);
    GetComponent<Renderer>().SetPropertyBlock(block);

with someColor being, for example, a public serialized property I just added to skeletonRenderer to demonstrate. You can see two crap test skeletons below that have the same material, but different colors as specified per my new skeletonRenderer property someColor...

Anyway, it's perhaps a moot point since they didn't seem to batch on my end. 🙁 Will keep digging for a bettter solution, but I think it should be totally doable without multiple material instances.

I'll actually give this a pass just to see if it works! Functional first, pretty second.

Anyways, I've budgetted for an unknown drawcall increase, and for now, having this not batch is more than survivable (only gonna' draw a handful at any given time).

Thanks for the idea, I'll report back in a few hours.

Quickie Report: Vacation and family time slows down progress expectedly, but I think I have batching. :rofl:

Excellent! I imagine I just did something stupid on my end. You should be able to do alot with custom properties moving forward. Have fun with it! 😃

شهر واحد لاحقا

Just a quick update now that I can: so far it's working like a charm as a quick & hacky solution. Even has batching! I notice, though, that these Blocks do not properly show change in inspector if I am setting a ton of custom PropertyBlocks in script. With that said, nothing some Debug.Logs couldn't fix.

Cheers.


Edit: 4.6.7 shows MaterialPropertyBlock changes in inspector now. :clap:


Mitch wrote

yep... this process pretty much sucks now.

ideally we'd be able to provide an alternative AtlasAsset to load from rather than just the one specified in the AtlasAssets array of the SkeletonDataAsset. No code exists in the runtimes to let you do that though. Ultimately what I think will happen is a delegate function will need to be created that says "GetAtlasAssets()" and you can override that when you want to when initializing a new skeleton.

Have you thought about this kind of access more recently? I'm curious to know what y'all are thinking about in terms of a potential road map.