I find it hard to describe this problem in words, which is why I made a video (45 seconds) to illustrate it. Here's a preview of the questions, please have a look at it on Vimeo: http://vimeo.com/epologee/perfect-crossfade

Using a linear crossfade the resulting image will have a 'dip' in transparency. How can I prevent this?

The issue of creating a flawless crossfade or dissolve of two images or shapes has been recurring to me in a number of fields over the last decade. First in video editing, then in Flash animation and now in iOS programming. When you start googling it, there are many workarounds to be found, but I really want to solve this without a hack this time.

The summary:
What is the name of the technique or curve to apply in crossfading two semi-transparent, same-colored bitmaps, if you want the resulting transparency to match the original of either one?

Is there a (mathematical) function to calculate the neccessary partial transparency/alpha values during the fade?

Are there programming languages that have these functions as a preset, similar to the ease in, ease out or ease in out functions found in ActionScript or Cocoa?

Update: In addition to the video, I've made a sample project (requires Xcode and iOS SDK) and posted it on github. It shows the same animation as the video but this time with squares: https://github.com/epologee/StackOverflow-Example-Code

  • 7
    Don't know anything about it but +1 for the video. – sebastiangeiger Nov 12 '11 at 13:49
  • Depends on how the over operator is implemented. See en.wikipedia.org/wiki/Alpha_channel – artistoex Nov 12 '11 at 14:16
  • I agree, @artistoex, there's something to that over operator, thanks for the link! However, if the answer is buried in there somewhere, I'm not seeing it :( – epologee Nov 13 '11 at 16:48
  • The mathematical representation of the over operator leads to an equation. Example over operator: C=alpha*c1+(alpha-1)*c2 yields alpha=(C+c2)/(c1+c2) (C being the result of mixing the two colours c1, c2). This means for this over operator, there is no function, which satisfies your condition. – artistoex Nov 14 '11 at 8:03
  • For C = alpha1*c1+alpha2*c2 (0<=alpha1, alpha2<=1), there is such function: alpha1=(C-alpha2*c2)/c1. – artistoex Nov 14 '11 at 8:06

I am afraid that's not possible. This is how transparency is calculated when two objects overlay: http://en.wikipedia.org/wiki/Alpha_compositing

Alpha compositing

One of the objects must have an opacity of 1 if you don't want the overlay area to be seen through.


I don't know what the name might be in the realm of video editing, but I'd call the curve an S-curve or sigmoid curve. It should be very simple to produce the cross-fade you're looking for in iOS using Core Animation's kCAMediaTimingFunctionEaseInEaseOut timing function. Just animate the alpha property of two views in opposite directions (one 0->1, one 1->0) using that timing function:

[UIView beginAnimations:@"crossfade" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
view1.alpha = 0.0;
view2.alpha = 1.0;
[UIView commitAnimations];

Note: You should really use the blocks-based animation methods instead of UIView's convenience methods. I used UIView's methods above because it's very easy to understand, and easy to type from memory. Using blocks isn't much more difficult, though.

Addendum: If you don't like UIViewAnimationEaseInOut, you can create your own timing function as described in Timing, Timespaces, and CAAnimation. That's a bit more advanced than the simple animation illustrated above, but it gives you all the control you want.

  • Sigmoid! That's already one step closer, thanks! The piece of code you provide doesn't work right away, for the setAnimationCurve takes a different parameter than kCAMediaTimingFunctionEaseInEaseOut. Could you have meant UIViewAnimationCurveEaseInOut? The problem with that curve is the same though (dip in the middle), because at any point in time, the two alpha values in a simple addition will equal 1.0, where as in my manually tweaked curve it needs to exceed 1.0 to get the desired results. – epologee Nov 12 '11 at 14:39
  • I see now... you're right about the constant -- I've updated the code in the answer. I've also added a link to docs that explain how to create your own timing functions. – Caleb Nov 12 '11 at 15:11
  • I do my animations with blocks, yet the gist is the same. The built in curves still don't apply, because of their symmetry, but the addendum paved the way to a custom CAMediaTimingFunction that matched the one I used in the After Effects video. Troubling is that there is not one sigmoid curve that fits every scenario, different starting levels of opacity will require different bezier positions to get rid of the 'dip'. There must be something I'm missing. – epologee Nov 13 '11 at 16:46
  • Hi @Caleb, I posted a sample project on GitHub (see post). The custom timing is helpful, but if you change the initialTransparency value, it's no use. You wouldn't have a clue what to try next? – epologee Nov 13 '11 at 23:39
  • 2
    A few more little bits to help Google searches; graphics programmers call the graph that you're talking about a "smoothstep". Highly mathy programmers will often call it a "hermite interpolator". And a simple equation to calculate one without trigonometry is: "3t^2 - 2t^3". – Trevor Powell Nov 14 '11 at 0:10

In computer graphics, this kind of function is called smoothstep. When used to crossfade, it determines the global alpha value for the composition.

If the input images have an alpha channel, you should first make sure that the alpha is premultiplied. Then, you can do the crossfade composition straightforwardly, using the smoothstep alpha on each channel [X = A*alpha + B*(1-alpha)], and expect reasonable results.


You can use the exponential decay function:

Alpha1(time) = 1 - exp(-time / (0.2 * transitionTime)); // fade in
Alpha2(time) = 1 - Alpha1(time); // fade out

Your graph looks more like:

Alpha1(time) = sin(time * 0.5 * pi / transitionTime); // fade in
Alpha2(time) = cos(time * 0.5 * pi / transitionTime); // fade out
  • Thanks @Danny. Actually, performing the 1 - Alpha1(time) equation won't take care of the dip, because two blended 0.5 alpha images won't result in an composited image with 1.0 alpha. The custom curves I drew are not mirrored vertically. – epologee Nov 16 '11 at 11:10
  • 1
    The 1-alpha was for the exponential decay, which I think is more suitable. For the sin/cos functions of course sin(t)=sqrt(1-sqr(cos(t)), however, calculating each one separately should be faster. – Danny Varod Nov 16 '11 at 12:17
  • If the issue were what the function of a similar curve might look like, your math is correct. However the issue is how to deal with the blending of two colors, e.g. how to get 40% blue + 40% blue to result in 80% blue. – epologee Nov 16 '11 at 13:36
  • That is easy to do but would result in bad looking saturation when sum of colors > 100%. – Danny Varod Dec 3 '11 at 11:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.