Author Topic: How to apply a shader effect on one sprite?  (Read 6744 times)

WinMain

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
How to apply a shader effect on one sprite?
« on: October 27, 2014, 05:24:13 AM »
I know how to apply the shader on a material,but I just want to apply a effect on one sprite in atlas.It's there some way to do this?

dilshod

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 7
  • Posts: 14
    • View Profile
Re: How to apply a shader effect on one sprite?
« Reply #1 on: October 27, 2014, 10:50:40 AM »
Here is my version of how it could be done. i'm going to use this in my current project.

UIShaderSprite.cs:
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. public class UIShaderSprite : UISprite {
  6.         Material mMaterial;
  7.         [HideInInspector][SerializeField] Shader mShader;
  8.  
  9.         // cache materials
  10.         static Dictionary<int, Dictionary<int, Material>> atlasMaterials = new Dictionary<int, Dictionary<int, Material>>();
  11.  
  12.         public override Material material {
  13.                 get {
  14.                         if (mShader != null) {
  15.                                 if (mMaterial == null || mChanged) {
  16.                                         Dictionary<int, Material> shaderMaterials;
  17.                                         if (!atlasMaterials.TryGetValue(atlas.GetInstanceID(), out shaderMaterials))
  18.                                                 atlasMaterials[atlas.GetInstanceID()] = shaderMaterials = new Dictionary<int, Material>();
  19.  
  20.                                         if (!shaderMaterials.TryGetValue(mShader.GetInstanceID(), out mMaterial) || mMaterial == null)
  21.                                                 shaderMaterials[mShader.GetInstanceID()] = mMaterial = new Material(base.material) {shader = mShader};
  22.                                 }
  23.                                 return mMaterial;
  24.                         }
  25.                         return base.material;
  26.                 }
  27.         }
  28. }
  29.  

Editor/UIShaderSpriteInspector.cs:
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections;
  4.  
  5. [CanEditMultipleObjects]
  6. [CustomEditor(typeof(UIShaderSprite), true)]
  7. public class UIShaderSpriteInspector : UISpriteInspector {
  8.  
  9.         protected override bool ShouldDrawProperties() {
  10.                 NGUIEditorTools.DrawProperty("Shader", serializedObject, "mShader", GUILayout.MinWidth(20f));
  11.                 return base.ShouldDrawProperties();
  12.         }
  13. }
  14.  

WinMain

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
Re: How to apply a shader effect on one sprite?
« Reply #2 on: October 27, 2014, 10:48:55 PM »
Here is my version of how it could be done. i'm going to use this in my current project.

UIShaderSprite.cs:
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. public class UIShaderSprite : UISprite {
  6.         Material mMaterial;
  7.         [HideInInspector][SerializeField] Shader mShader;
  8.  
  9.         // cache materials
  10.         static Dictionary<int, Dictionary<int, Material>> atlasMaterials = new Dictionary<int, Dictionary<int, Material>>();
  11.  
  12.         public override Material material {
  13.                 get {
  14.                         if (mShader != null) {
  15.                                 if (mMaterial == null || mChanged) {
  16.                                         Dictionary<int, Material> shaderMaterials;
  17.                                         if (!atlasMaterials.TryGetValue(atlas.GetInstanceID(), out shaderMaterials))
  18.                                                 atlasMaterials[atlas.GetInstanceID()] = shaderMaterials = new Dictionary<int, Material>();
  19.  
  20.                                         if (!shaderMaterials.TryGetValue(mShader.GetInstanceID(), out mMaterial) || mMaterial == null)
  21.                                                 shaderMaterials[mShader.GetInstanceID()] = mMaterial = new Material(base.material) {shader = mShader};
  22.                                 }
  23.                                 return mMaterial;
  24.                         }
  25.                         return base.material;
  26.                 }
  27.         }
  28. }
  29.  

Editor/UIShaderSpriteInspector.cs:
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections;
  4.  
  5. [CanEditMultipleObjects]
  6. [CustomEditor(typeof(UIShaderSprite), true)]
  7. public class UIShaderSpriteInspector : UISpriteInspector {
  8.  
  9.         protected override bool ShouldDrawProperties() {
  10.                 NGUIEditorTools.DrawProperty("Shader", serializedObject, "mShader", GUILayout.MinWidth(20f));
  11.                 return base.ShouldDrawProperties();
  12.         }
  13. }
  14.  
Thank you for your idea.But I have one question is,whether this way will make the drawcall rise?Becase if there are too many sprites in atlas,there will be too many materials.

dilshod

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 7
  • Posts: 14
    • View Profile
Re: How to apply a shader effect on one sprite?
« Reply #3 on: October 28, 2014, 01:38:40 AM »
Nope, i'm not creating new material for each sprite, i'm creating new material for each shader and atlas, that's why there is a cache for materials.
If you put hundreds of different sprites with same shader and same atlas in one depth, they will add only one (or two) draw call.

WinMain

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
Re: How to apply a shader effect on one sprite?
« Reply #4 on: November 04, 2014, 04:53:39 AM »
thanks for your solution dilshod.

kimsama

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 9
    • View Profile
Re: How to apply a shader effect on one sprite?
« Reply #5 on: December 11, 2014, 03:22:55 AM »
See UIShaderSprite for the working copy of this thread.

You can find it on the following github repository:

https://github.com/kimsama/Unity-NGUIExtension

As my experiments, it needs to call panel.RebuildAllDrawCalls() to correctly apply a new shader which is differenct to what NGUI applies in UIDrawCall.UpdateMaterial() call.

WinMain

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
Re: How to apply a shader effect on one sprite?
« Reply #6 on: January 05, 2015, 11:27:01 PM »
See UIShaderSprite for the working copy of this thread.

You can find it on the following github repository:

https://github.com/kimsama/Unity-NGUIExtension

As my experiments, it needs to call panel.RebuildAllDrawCalls() to correctly apply a new shader which is differenct to what NGUI applies in UIDrawCall.UpdateMaterial() call.
Awesome,Thank you so much.