• Unity
  • Custom Material / Shader on Spine Animation

Related Discussions
...

So here is a new topic about Material/Shader handling (yay). I'm a new to those Unity matters so bear with me.
I just wanna tween a flash value on my characters shader when they get hit, so they'd become white for a split second. For others objects that aren't Spine animations, I just add my FlashMaterial on them, which has a ColorFlash shader on it, and it works fine:

sprite.material.SetFloat("_FlashAmount", 0.5f);
sprite.material.DOFloat(0f, "_FlashAmount", 0.5f);

QUESTION: how to do that with Spine animations since they already have a material and shader ? I tried and succeed to replace the material using Pharan suggestion:

void OnWillRenderObject () {
     if (meshRenderer.sharedMaterial == materialToReplace) {
         meshRenderer.sharedMaterial = meterialIWantToUse;
      }
}

...but doing so it turns all character's parts into white boxes (not good). That leads me to think the spine animation actually requires its origin material to work properly...?
So instead of changing the material, I tried to change only the shader at run time. As a test, I dragged and dropped the ColorFlash to replace Spine/Skeleton and it actually works. I could edit the _FlashValue to adjust the white flash value and it looks good on the character. Unfortunately I can't do it by code. I tried this:

meshRenderer.sharedMaterial.shader = meterialIWantToUse.shader;

and tons of other shenanigans but it won't work...

Any leads?

We were just beating around the bush, of course.

 Loading Image

The magic of Renderer.SetPropertyBlock
The Spine/Skeleton Fillable shader, and a sample script is included:
https://gist.github.com/pharan/7a06e2a5239f3893d79b8852c249642f

EDIT: This post has been edited with a new link. The new sample shader is named Skeleton Fill instead of Skeleton Fillable

Thanks for the Lucky Luke answer. It's what I need. Though how am I supposed to change my characters materials shaders to Spine/Skeleton Fillable when they are all systematically replaced by Spine/Skeleton when I hit Play? I'm so confused right now... two days on character blinking :nerd:

They're not replaced with Spine/Skeleton.
Just change the source Material's shader that's used by the atlas asset and don't change the materials anywhere else. It'll work. See the sample scene and sample spineboy assets.

They do seem to be replaced actually... But I think I just figured why, I guess it's because I use:

SkeletonAnimation.AddToGameObject(gameObject, skeletonDataAsset)

I'm digging into the spine-runtime to see how I could directly change the source Material for all instantiated Spine skeleton, any clue?

I'm the one who added SkeletonAnimation.AddToGameObject.
Nothing about that sets shaders or whatever. It just spawns the SkeletonAnimation normally, using the SkeletonDataAsset you give it. So it goes through the SkeletonDataAsset to the AtlasAsset to the assigned material on that asset and that's what it uses.

The material's shader isn't replaced with Spine/Skeleton.
It just uses the Material asset assigned to the Atlas asset. So if that happens to be using Spine/Skeleton, it'll use that because it's using that exact Material.

If you change that to Unlit/Transparent, it'll use Unlit/Transparent.

So you just set that one.

Oh damn, I had a forgotten piece of code which was still replacing the material in my back, my bad.

Now it works obviously, I can tween it and everything, very cool, thanks..


29 Fév 2016, 15:05


Mmmmh, is there any chance I can find a way to apply that kind of filters/flash to a single slot of my character? I just want my shield to flash upon blocking.
Since I didn't find a SetPropertyBlock method on the shield slot, I tried to play with its RGB properties but I can't make it completely white apparently.

SetPropertyBlock is a Unity Renderer method. Slots wouldn't have it.
Making just that one slot flash is tricky for now, but not for long.
That's definitely related to the topic here: Per-instance material

Looks like we've found a good way to do it though.
Will probably make it into the official runtime this week. Just need to hammer out some details.

Perfect, looking forwards to the update then. No hurry on my end tho, I'm in for 2 years...

@SoulGame.
Per-slot material is up.
Check this thread for the sample code: Per-instance material
If you're updating through the unitypackage, please read the PSA here: Noteworthy Spine-Unity Topics
ie. delete the old SkeletonJson.cs if you have that file.

12일 후

Nice! Looking into it, thanks for the heads up.


15 Mars 2016, 15:25


Based on your example, I've made a fillSlot function that works well, it makes my shield flashes just as intended which is great. Problem is, fillSlot has no effect after I call fillSkeleton, which is the function I use to make the whole animation flash. So basically, once my character gets hit, his shield won't flash anymore when he blocks.

I ensured that the CustomSlotMaterials was still present and not overwritten so I'm not sure at all why this happen. Am I using the system all wrong or is this is an unintended behavior? Here are both functions:

public void fillSlot (string pSlotName, Color pColor, float pPower, float pDuration, Material pMaterial) {
    Slot slot = skelAnima.skeleton.FindSlot(pSlotName);

// Add the material if no material assigned to that slot
if (!skelAnima.CustomSlotMaterials.ContainsKey(slot)) {
    skelAnima.CustomSlotMaterials[slot] = pMaterial;
}  

Material material = skelAnima.CustomSlotMaterials[slot];

material.SetFloat("_FillPhase", 0);
material.SetColor("_FillColor", pColor);
DOTween.To(() => material.GetFloat("_FillPhase"), x => material.SetFloat("_FillPhase", x), pPower, pDuration).From();
}

(fillSkeleton works well no matter what)

public void fillSkeleton (Color pColor, float pPower, float pDuration) {
    materialBlock.SetFloat("_FillPhase", 0);
    materialBlock.SetColor("_FillColor", pColor);
    DOTween.To(() => materialBlock.GetFloat("_FillPhase"), x => materialBlock.SetFloat("_FillPhase", x), pPower, pDuration).From().OnUpdate(flashUpdate);
}

NB: regarding Materials :

  • fillSkeleton uses the origin Material with SkeletonFillable shader.
  • fillSlot uses a copy of this Material. (that seemed like the only way to display the shield texture properly)

When your renderer has a MaterialPropertyBlock, it overrides all the properties set on any materials you have. So if you set any properties on the materials themselves, they will be overridden. The Renderer's MaterialPropertyBlock takes priority.

This is supposed to be beneficial since this allows you to share materials between renderers and each can have their own material properties.

But if you plan to ALSO control properties per material, you need to remove the effects of MaterialPropertyBlock (since the whole point of it is to override all of the material's properties).

To clear the renderer's MaterialPropertyBlock, you need to call these two:

materialBlock.Clear();
skeletonAnimation.GetComponent<MeshRenderer>().SetPropertyBlock(materialBlock);
5일 후

Oh I see, that explains a lot.
Then I guess I must forget PropertyBlock and go with individual materials to handle both individual effects and overall effects . Unless it's more cost effective to actually Set the PropertyBlock before each overall effects and Clear it afterwards... But that doesn't seem right. Thanks!

일 년 후
Pharan wrote

We were just beating around the bush, of course.

 Loading Image

The magic of Renderer.SetPropertyBlock
The Spine/Skeleton Fillable shader, and a sample script is included:
https://gist.github.com/pharan/7a06e2a5239f3893d79b8852c249642f

EDIT: This post has been edited with a new link. The new sample shader is named Skeleton Fill instead of Skeleton Fillable

:sweat: Well...I suck at coding as an artist really.
So can I have a whole sample of the being shot animation?