Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to do flashing for sprites?

Discussion in 'Scripting' started by Jay-Pavlina, Apr 20, 2012.

  1. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    What would be the most efficient way to do flashing for sprites similar to how Mario flashes when he gets a star in Super Mario Bros.? Is this possible to do with a shader? I've included two examples of the effect I need. Thank you.

     
  2. kablammyman

    kablammyman

    Joined:
    Nov 22, 2010
    Posts:
    507
    Last edited: Apr 20, 2012
  3. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    That tints all the colors on the sprite by the same color. I need to be able to replace colors individually.
     
  4. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    The best way to do it depends on the actual effect you want to achieve. I'd do the above two differently. I couldn't give a recommendation without seeing your artwork and a mockup.
     
  5. jessee03

    jessee03

    Joined:
    Apr 27, 2011
    Posts:
    729
    why not just use a sprite sheet and animate through it like the sprite sheet is setup?
     
    Miscellaneous likes this.
  6. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    If the effect is simple, as with Mario and Mega Man, that would be an inefficient use of memory. It would be easy to deal with, though, so it's a more efficient use of time, if you have the memory to spare.
     
  7. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    That is the artwork I'm using and it's the exact effect I want to achieve. It's for the Unity port of Super Mario Bros. Crossover.

    The characters will be moving while flashing and if I use a separate sprite sheet for each possible color combination it will take up way too much memory.
     
  8. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,697
    Why not have a full animation for each state and each mode? Then just transistion as required.
     
  9. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    I need to be able to set the colors with code because they change depending on many different factors. What I'm really looking for is an efficient way to replace colors multiple times per second.
     
  10. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,697
    Why not have one block of sprites in greyscale. Then adding color should be no biggie.
     
  11. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    Ah-hah! That's why I recognized your avatar! Why are you porting? How is that not shut down by now?! :-O

    I need more information on that. Are there set color palettes, as above, or are there going to be wildly lerping values?

    Also, are you able to use a quad for each pixel, or is that too much of a pain? As far as I can imagine, that would be the most efficient route, but if you don't have a workflow for it, it doesn't matter.

    I don't see how that makes sense. The colors aren't just being multiplied in.
     
    Last edited: Apr 21, 2012
  12. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    Lots of reasons, but mainly because Unity is cool and I wanted to learn how to use it.

    All of the color palettes are set ahead of time. Basically I have an array of source colors and an array of colors that need to be set to depending on what's happening.

    I use one quad for each sprite, so it probably wouldn't work to use one for each pixel. I'm open to trying different things though. I haven't really started making the game yet so my workflow is not fully set yet.
     
    Last edited: Apr 21, 2012
  13. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,697
    If you have a grey scale base, then you can add some type of shader, or adjust the color itself. The greyness or lack there of will just give greater or lesser intensity.
     
  14. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    Here's what I recommend. If you take this approach, I'd like to hear your workflow, because I think I was a bit slow at it, using lots of eyedropper, magic wand with low tolerance/discontiguous, and one pixel marqueeing.

    You'll make two textures. One of them (the one that looks like the character) is Alpha 8, to be memory efficient. You find out how many colored areas you need (11 for Mega Man, by my calculations. 10 actual colored areas, plus one for the cutout), and select the next higher power of two up. Divide 256 by that, and you'll know how far apart to space the greyscale values in the key textures (16 bits apart for mega man). I used white as the color to discard, but the shader can be modified to deal with whatever. White or black should yield the fastest results.

    You'll then need to populate a texture with actual color values. This can be set up in row or columns, but I used rows. Take a look at these screenshots, and check out the package. You might get what's going on by doing that, but ask any questions otherwise. If you're using Windows, you'll have to force OpenGL; we can work on that if necessary. I recommend manipulating the "Key Y" slider, for fun and illustration, after opening the scene.

    How does this approach compare to what you did in Flash?

    P.S. I added the border because Unity actually expands all textures to powers of two, distorting pixel art. You'd probably want to set up the border differently.
     

    Attached Files:

    Last edited: Apr 21, 2012
    MaxEden likes this.
  15. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    Wow, that is crazy Jessy. Thank you for going above and beyond with all your hard work. Since I know nothing about shaders and am pretty new to Unity, I have tons of questions.

    First, let me show you how I was doing it in Flash. Here is Mega Man's 16-bit sprite sheet.



    And I have a separate file for each character that takes care of all the color replacing and flashing. This is what it looks like for 16-bit Mega Man:



    I'm not gonna explain exactly how it works, but the main point is that the left column is the colors on the sheet. It gets those colors, then replaces them with the colors to the right depending on what's going on. In Flash, I just replaced the colors directly on the sprite sheet (equivalent to Unity's Texture2d.SetPixels method).

    The thing I noticed about your proposal is that there is no row with the original colors, so I don't understand how it knows which color to replace each shade of gray with. Also, does it need to be gray, or is it possible to use it the way I have it set up on the sprite sheet. A lot of my sprite sheets are made by fans, and it's just easier to work with if I don't have to modify the colors on the sheet.

    Is this shader fast enough to use on everything even when it's not flashing? Because I change colors of stuff depending on what level it is, but it doesn't change again until the level is over. I was gonna use Texture2d.SetPixels for that, but I was just wondering if it's possible to use this or if that will cause the game to run too slow.

    Anyway thank you so much for helping me out. :)
     
  16. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    The shades of gray are stored as 0-1 values. Black maps to the left pixel of the color values sheet, and goes up in increments of 16 bits (.0625 of the way across the sheet). It would probably be best to have the second color be at 1/32 + 1/16, instead of just 1/16, so that the color is sampled right in the center of the texel, but I forgot to do that. It still worked out. Like I said, I didn't do a fast job of it. Also, the order of greyscale values and colors is totally arbitrary. I kind of worked from the outline, to lighter areas, ending with the face.

    I don't know how'd you do it with your sheets, in a shader. I googled it, and came up with Farfarer doing something very similar to what I posted here! ;-) If it's fast enough to script texture changes, do that. If you need to offload work to the GPU, you could try scripting a conversion to what I did, in the Editor. It looks like you could get away with rows/columns of 128 pixels.

    It's not very heavy, nor is most any shader used for 2D stuff. I might switch to a standard unlit cutout/blend shader, when possible, if you're concerned about battery, though. But the blending or "alpha testing", which are unavoidable if you don't "model" the pixel art with denser meshes, would be the potential bottleneck.

    Thanks for allowing me to live some of my childhood fantasies, with SMB Crossover! :-D
     
    Last edited: Apr 21, 2012
  17. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    I bet I could convert the sheets to the gray version when the game is started so that I could still use my current sheets. I already saw that other post, but I didn't understand it. But it does look like it's a similar technique. I noticed in that post that he decided to use the red and green channels to get more than 256 colors. I'll have to look into that.

    I was really just trying to see what my options were for the color changing, so thanks for enlightening me a bit. If I decide to go this route I'll probably have more questions. This technique would be faster than using set pixels and swapping textures continuously right? Also why would my rows and columns be limited to 128 pixels? My current palette sheet for Mega Man is 264 x 801 pixels because it holds colors for all of his skins.

    Edit: Actually, I don't think I'd ever need more than 256 colors on the source sheet.
     
    Last edited: Apr 21, 2012
  18. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    That's my prediction, but it depends on how much is changing per-frame. It doesn't matter how efficient your algorithm for changing pixels is, if you need to send a lot of texture data to the GPU all the time. If you can keep textures cached near the hardware that works with it, the speed of light won't be as much of an antagonist to you. Also, I don't know any way that a CPU could keep up with the GPU lookup approach I offered, but whether that amounts to a time difference that matters to a human, I don't know. You'd have to profile your own game, which involves much more than just the actions this thread is about. If you've already got some textures and code that works, try it out and see if there's any reason to try to improve performance.

    I was basing 128 on what I see in your color replacement sheet. I see blocks of 24x6 (144), but as far as I can tell, there are 7x6 blocks that aren't doing anything, which gets you below 128. There may be other unnecessary areas, or I may be totally off-base on this, due to my incomplete understanding of it.
     
    Last edited: Apr 21, 2012
  19. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    I don't have any code written yet, that's why I was trying to figure out which approach would be faster. I don't have Unity Pro either so I can't profile it, and I don't have any Apple devices to test mobile performance. I don't really understand which parts the CPU does and the GPU does.

    The only way to learn about it is to try it though. Thanks for your help.
     
  20. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    An easier method may be to have a shader which simply swaps around the RGB values, giving you:

    RGB
    RBG
    GRB
    GBR
    BRG
    BGR

    etc.. that's a fair few flashy colour cycling combinations and should look sufficiently retro? it is also pretty easy to do in a shader? As for overall brightening (flashes etc) you can just multiply them up.

    Just a thought!

    Although I am mega impressed by Jessy's idea above and would use that.
     
    Last edited: Apr 21, 2012
  21. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    I was talking more about a direct translation between your ActionScript and whatever you're using for Unity (I recommend C#).

    You can get some good info from the framerate, if you leave Application.targetFrameRate at -1. Here's one counter. All devices will have their quirks, but for the most part, you'll get the same performance differences on all devices, just multiplied based on processing power. e.g. If the technique I offered here were to make your game go from 800 FPS to 850 FPS – a useless increase on a desktop – it might possibly mean an actual noticeable difference from 30 to 60 FPS on some mobile device. You'll have to find out where you care; getting this into the App Store might be possible, based on all the bootleg Nintendo franchise stuff there, but doing so might just be inviting legal trouble. You'd probably know better than I would, based on your experience to this point.

    Pretty much everything that you do in a script will be performed on the CPU. The GPU stores some data locally, gets other data per-frame from the CPU (like transformation matrices and anything you modified in the mesh or displayed textures), and renders everything using shader instructions and vendor-specific tricks that you have no control over. The CPU is faster than the GPU, but only when you're not doing massively parallel operations, like texture lookups per-pixel, on a transformed polygon, which is why GPUs were invented, and continue to be used. Their architecture involves hundreds or thousands of cores, each generally performing small programs on the same data, instead of a handful of cores, working on all kinds of different data, with many instructions. The CPU is almost universally easier to work with.

    I think that the code for your palette switching could be really fast, but because rendering needs to happen on the GPU, it's not CPU speed you need to worry about; it's the communication between the two. Try to minimize the data (textures) that gets modified and uploaded to the GPU. This may involves using fewer sprite sheets, but a balance needs to be struck – there's some acceptable window for all of the possibilities for creating the the graphics and code. The window becomes larger as hardware progresses; I'm thinking that it's going to be pretty difficult for you to get a bad framerate out of anything you do with this project. My opinion is that your experience with Flash has made you paranoid about performance; I'm hoping, and believing, Unity will treat you better.

    There may be something you could do with render textures, but without Unity Pro, that's not possible. I don't have experience with my theories of how you'd do that, either.

    Try some stuff, and when you have issues, come around here with questions, if you think someone else could help you move forward, with information you couldn't find.

    Har har. :p
     
    Last edited: Apr 21, 2012
  22. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    I'm definitely using C#. I would not touch javascript with a ten foot pole.

    I'm not putting SMBC on the app store, but I'm building a 2D platformer engine that I can use for other games. That's why I want it to be designed really well.

    You're talking about the texture swapping technique right? I got scared when I read the docs for the Texture2D.Apply method. It says "This is a potentially expensive operation, so you'll want to change as many pixels as possible between Apply calls." That made me think I couldn't use it for flashing. So you are saying it might be ok if I keep the textures small? My idea was to still use the same sprite sheets, but whenever something flashes, I'll temporarily copy the bigger texture into a smaller texture that is only the size of the current sprite, so it'd probably be like 32 x 32 at the most, and I could change the pixels on that. I was worried it would be too slow, but it sounds like you're saying maybe I should try it. That's how I did it in Flash, but "modifying a texture and uploading it to the GPU" sounds like it's really expensive. Flash didn't have textures, only bitmaps.


    Yes that's true. The reason I get worried about performance is because the music in the game is emulated. I am hoping Unity will be faster at emulating the music. When I play Super Nintendo music, the game has to emulate the sound card of a Super Nintendo, and that can be an expensive operation. I'm hoping the C# version of the emulator will be faster than the C++ version I ran through Flash. I wish I could run C++ plugins in the browser, then it'd be super fast. I couldn't find any way to do it though. :(

    Thanks. I didn't get much help with my other questions so this is the first time I'm seeing how helpful the forums can be.
     
  23. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    Yes. Or if you don't modify many textures. Even if you only modify a small amount of pixels on a texture, the GPU will need the whole thing resent. Not having to worry about compression or mipmaps will help.

    Expensive in terms of time at least – literally due mostly to the distance between physical components, as far as my understanding goes. Your approach sounds pretty reasonable to me, but I've never tried it.

    Sorry to hear that. I hadn't read your other posts, but unfortunately, I don't have anything useful to respond with to them at this time. I got delete-happy on my RSS feed after Unity's popularity exploded years ago. There are too many threads nowadays that are inane, or have been answered countless times before, for me to get excited about checking the forum like I used to be. I bet there are a lot of potentially helpful people who fall into the same boat, now; I've heard some of them talk about it. Thanks for bringing an interesting topic around, though!
     
  24. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    I agree. I think it's because Unity's market includes both professionals and hobbyists. There are a lot of young people posting simple questions that can be answered with a quick search. A lot of threads seem to go unanswered because they get swallowed into the massive pool of random topics. And there's also Unity Answers, which is an entirely different thing, but it basically falls into the same boat. I've actually had more success by PMing people that seemed to know about topics I had questions about.

    Anyway, I think I'm going to attempt your method because I want to learn about shaders and it's something new and different. My flashing code in the Flash version is very sloppy so I need to redo it anyway. You seem like you know a lot about Unity and are very friendly, so I may PM you with questions about other topics if that's alright.
     
  25. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I check the forums whenever I have a nice cuppa or smoke my e-cig :) usually during breaks. It's fairly fun and I don't mind helping out. There's a lot of annoying people who never read docs like ever, but once in a while you get a well-worded post that begs for an answer like this thread.
     
  26. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    That's cool. I wrote it in GLSL (ES in particular) because that's what I know best, and is what the platforms I care most about right now use, but you'll need Cg code for Windows and Flash. (A surface shader would work, but is overkill, given your lack of dependency on lighting.) Ippokratis, who is an awesome member of the community, wrote this Cg–Unity primer. Maybe you could check it out, and try to translate what I made into Cg? That would help me learn Cg, too, if you have any success, and share it.

    Ha, thanks! I usually prefer that people post questions publicly, and PM me a link, so that many more people can be helped by any information I can share, and so that other people can help. However, it's fine for people to talk to me privately if they don't want the subject of their questions out in the open, or if the scope of the issue is big enough to warrant contract work.
     
  27. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    Thanks. Maybe that will help me learn how shaders work.

    Great idea. I have a question about networking I wasn't able to get much help on before (unless it was just a bad question), so I might do that soon.
     
  28. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    Hi,

    Exploding Rabbit:
    Perhaps the Rage Pixel package could help you build an efficient workflow for creating - using pixel art in Unity.

    Jessy :
    Thanks a lot for sharing the code, it is much appreciated. The use of palletes + Alpha8 has a big potential in building memory - efficient particle effects too. There is a presentation from Valve where they describe how they used this approach to obtain three different colored "muzzles" from one alpha 8 and three palletes with a higher degree of color control than tint gives. The main drawback that remains ( for me using this technique ) is how to create the assets, i.e the alpha and the pallete, in an efficient way.
    Here is an attempt to "translate" the shader code you posted in Cg, I wonder if we could skip the need to use discard ( = clip(-1) ) somehow.
    Code (csharp):
    1.  
    2. Shader "Color Keys Cg"
    3. {
    4.     Properties
    5.     {
    6.         _Cutoff ("Cutoff", Float) = .97
    7.         _KeyY ("Key Y", Float) = 0
    8.         _MainTex ("Key X texture (Alpha)", 2D) = ""
    9.         _Colors ("Colors", 2D) = ""
    10.     }
    11.  
    12.     SubShader
    13.     {
    14.         Pass
    15.         {
    16.             //GLSLPROGRAM
    17.             CGPROGRAM
    18.             //#ifdef VERTEX
    19.             //#endif
    20.             #pragma vertex vert
    21.             //#ifdef FRAGMENT
    22.             //#endif
    23.             #pragma fragment frag
    24.             #pragma fragmentoption ARB_precision_hint_fastest
    25.             #include "UnityCG.cginc"
    26.            
    27.             //varying mediump vec2 uv;
    28.            
    29.             struct v2f
    30.                 {
    31.                    float4  pos : SV_POSITION;
    32.                    float2  uv : TEXCOORD0;
    33.                 };
    34.            
    35.            
    36.             //uniform mediump vec4 _MainTex_ST;
    37.             float4 _MainTex_ST;
    38.            
    39.             v2f vert (appdata_tan v)
    40.             {
    41.                 v2f o;
    42.                 //gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    43.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    44.                 //uv = gl_MultiTexCoord0.xy + _MainTex_ST.xy + _MainTex_ST.zw;
    45.                 //o.uv = v.texcoord.xy;
    46.                 o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    47.                 return o;
    48.             }
    49.            
    50.             //uniform sampler2D _MainTex, _Colors;
    51.             sampler2D _MainTex, _Colors;
    52.             //uniform highp float _Cutoff, _KeyY;
    53.             float _Cutoff, _KeyY;
    54.             float4 frag(v2f i) : COLOR
    55.             {
    56.                 //highp float keyX = texture2D(_MainTex, uv).a;
    57.                 float keyX = tex2D(_MainTex, i.uv).a;
    58.                 //if (keyX > _Cutoff) discard;
    59.                 clip(  keyX > _Cutoff ? -1:1 );
    60.                 //Same results can be obtained with if (keyX > _Cutoff) clip (-1);
    61.                 return tex2D(_Colors, half2(keyX, _KeyY));
    62.             }        
    63.             //ENDGLSL
    64.             ENDCG
    65.         }
    66.     }
    67. }
    68.  
    Kind regards,
    -Ippokratis
     
    MaxEden likes this.