Page 1 of 2

Gradual color change

Posted: Sun Sep 24, 2017 3:40 pm
by DRW
In my next game, there are several sections that might use different colors, but where you can still move from one section to the other without a hard cut.

For this, I'd like to do a color change like in "Link's Awakening DX":
www.youtube.com/watch?v=YzEU19PUVuE&t=13m19s

Do you know of any automatic algorithm with which I can do the color change for an NES palette?

I'm not talking about how to put this into PPU. I'm talking about a good way to transform one color into another one.

Let's say I have color $05 in one screen and color $2A in the next. And I want to change one color into the other one with two steps in between. But I don't want to build a manual lookup array of every single color tranforming into every other color.

Is there some automatism I can apply here?

Re: Gradual color change

Posted: Sun Sep 24, 2017 4:03 pm
by tokumaru
Grays excluded, the NES palette is circular, like a color wheel, so you can generally, "slide" left or right (whichever way is shorter) to morph one hue into another. The brightness can also be animated like this, as we usually do when fading.

If you want a fixed number of steps between 2 states, you'll have to calculate the difference between the source and target values (hue and brightness separately) and then find N intermediary points in those ranges.

Re: Gradual color change

Posted: Sun Sep 24, 2017 11:36 pm
by DRW
tokumaru wrote:Grays excluded, the NES palette is circular, like a color wheel, so you can generally, "slide" left or right (whichever way is shorter) to morph one hue into another.
Yeah, that might be a way. Thanks for the tip.I never noticed that the palette actually equals a color wheel.
tokumaru wrote:The brightness can also be animated like this, as we usually do when fading.
When I want to fade into black, I would do the following:
Subtract each color value with 16. If the upper four bits are 0, then the next step will be that the color becomes black.
Is this how you would do it as well?
tokumaru wrote:If you want a fixed number of steps between 2 states, you'll have to calculate the difference between the source and target values (hue and brightness separately) and then find N intermediary points in those ranges.
Could be a bit difficult with 48 usable colors. I guess it's not really necessary that every color has the same number of steps.

Re: Gradual color change

Posted: Mon Sep 25, 2017 1:48 am
by pubby
It would be easiest to precompute the palettes needed rather than computing them on the fly. Do what Tokumaru said, just don't try doing it in assembly.

Re: Gradual color change

Posted: Mon Sep 25, 2017 2:08 am
by DRW
pubby wrote:It would be easiest to precompute the palettes needed rather than computing them on the fly.
That's exactly what I want to avoid: Manually designing each color change for each section combination.
pubby wrote:just don't try doing it in assembly.
What does the programming language have to do with it?

Re: Gradual color change

Posted: Mon Sep 25, 2017 2:37 am
by Bregalad
You should separate the palette entry between the "hue" (low nybble) and "luminousity" (high nybble) components, and slide those separatedly. Luminosity is the easier, since you just add or substract one, until you get to the number you want.

Hue is a bit more complicated, but doable. The "lazy" way is to simply add one until you get the number you want, if you attain the $0d column reset to the $01 column. But this can take a long time as you might rotate through the entiere palette doing this. So in order to be quicker, you'd want to compute the "distance" between the hues, and go either left (+$01) or right (-$01) through the palette columns, taking the shorter path. In the worst case where the hue difference is 6, the distance is the same in either direction. In the case either the start or target column is $00 it's a special case because you have to jump in our out of this column at some point. Similarly, the colour black $0f is a special case.

The effect as a whole can have a duration up to 6 steps, but you'll have to find a way to stay at the target hue and/or saturation once you reach them, just like you can stay to black when fading the palette out.

Re: Gradual color change

Posted: Mon Sep 25, 2017 3:30 am
by DRW
Yeah, the description that you gave is what I would have done anyway after the above hints:
Distinction between horizontal and vertical values.
And finding the shortest path.

I just don't know yet how I should decide which way to take when the other color is six steps away.
And what to do if a color has to move into white, gray or black.

Also, I'm not sure whether I should update each color whenever possible (so that a color that goes through six steps actually shows all six steps) or whether I should declare some fixed points in the transition where all colors are updated (so that the six steps are only done in memory, but only three of them are shown on the screen).

Re: Gradual color change

Posted: Mon Sep 25, 2017 3:36 am
by Bregalad
DRW wrote: Also, I'm not sure whether I should update each color whenever possible (so that a color that goes through six steps actually shows all six steps) or whether I should declare some fixed points in the transition where all colors are updated (so that the six steps are only done in memory, but only three of them are shown on the screen).
Unless the effect needs to be faster than 6 frames, I do not see the point of not showing all steps.
I just don't know yet how I should decide which way to take when the other color is six steps away.
It really doesn't matter, you just have to pick one "preferred" direction that applies in those cases.
And what to do if a color has to move into white, gray or black.
The simplest is to avoid using those colours in the palettes that will go through your effect ^^. If you still need those colours with the effect, you'll have to handle the cases individually and code them as special cases.

Another way would be to have your own luminosity that extends the NES luminosity, for example it accepts values 0 to 5, but when display it you convert it to NES palette, for instance $0x always convert to $0f, $1x converts to $0x, and so forth until $4x which converts to $3x, and eventually $5x which converts to $30.

That still doesn't solve the problem of jumping to and from the gray column, but at least it allows easily fading to and from black, as well as to and from white, using the normal algorithm, but you just have to convert your palette colour before displaying it.

Using the same concept you could extend this and have a full HSL palette internally, do a gradual change there and "convert" it to NES palette before displaying, however I do think it's overkill. But if you really need smooth transitions and you need support for all colours including black, whites and grays, this is the most appropriate solution.
Something like this pseudocode to convert from HSL to nearest NES palette colour.

Code: Select all


convert_HSL_to_NES(H, S, L):
   if L == L_MAX :
      return $30

   elseif L == 0 :
      return $0f

   else if S < SAT_MAX :
      return (L*3/L_MAX) << 4

   else :
      hue = 12*H/H_MAX + 1
      lum = 4*l/L_MAX
      return lum << 4 + hue      

Re: Gradual color change

Posted: Mon Sep 25, 2017 3:51 am
by DRW
Bregalad wrote:Unless the effect needs to be faster than 6 frames, I do not see the point of not showing all steps.
Because in this case, the colors will switch at many different times. Not only will there be more or less steps. But colors that are six steps away will be updated at other times from colors that are four steps away.
Bregalad wrote:The simplest is to avoid using those colours in the palettes that will go through your effect ^^.
Unlikely.
Bregalad wrote:If you still need those colours with the effect, you'll have to handle the cases individually and code them as special cases.
Well, yes, but making something up for handling these cases is the interesting part. Actually programming it is not an issue.

I don't think I'll have some kind of internal abstract palette. I'll simply invent something for the grey values.

Re: Gradual color change

Posted: Mon Sep 25, 2017 6:53 am
by Dwedit
Image
Why yes, NES palette, I see you clearly in the YIQ color plane. Divide it into twelfths.

Re: Gradual color change

Posted: Mon Sep 25, 2017 7:06 am
by tokumaru
Since the grayscale columns in the NES palette are all fucked up, I usually give hue 0 special treatment, and I use a look-up table to convert brightness values into the final hardware colors.

Re: Gradual color change

Posted: Mon Sep 25, 2017 7:26 am
by DRW
Of course column 0 needs special treatment. The color change algorithm will only work on column 1 to C. This one is pretty obvious.

The question is just: How could we treat transformation from and to the grayscale values?

Brightness is simple: Conversion from one brightness to another is done as if black was actually color $00, white $30 and gray $10 and $20 instead of the constellation that they have in the moment.

But how do I gradually transform black into a specific green? Or gray into orange?

Re: Gradual color change

Posted: Mon Sep 25, 2017 7:37 am
by nesrocks
In my opinion, transitioning from black/grays/white to any color:
1 - jump to the correct hue instantly
2 - add/subtract brightness untill you get the final color

Re: Gradual color change

Posted: Mon Sep 25, 2017 7:46 am
by DRW
Sounds like a plan.

Re: Gradual color change

Posted: Mon Sep 25, 2017 8:01 am
by tepples
DRW wrote:I just don't know yet how I should decide which way to take when the other color is six steps away.
When the colors are five or six hues apart, you're cutting through the middle of the YUV/YIQ plane. This means you can go through the gray of roughly the same brightness. For example, for $22 to $28, use $22, $10, $28.