# Fade Effect - What's with the ghost?

**URL:** <https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891>\
**Category:** Coding Questions\
**Created:** [March 22, 2020, 12:42am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891 "2020-03-22T00:42:13Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tomfoolery](https://avatars.discourse-cdn.com/v4/letter/t/97f17d/32.png) [@Tomfoolery](https://discourse.processing.org/u/Tomfoolery)\
**Post date:** [March 22, 2020, 12:42am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/1 "2020-03-22T00:42:13Z")

</div>

My intention is to create a fade effect for thousands of shapes on the canvas (They appear, and then fade into blackness).  
This is the solution I came up with, and have found other people using.

```auto
void draw()
{
    fill(0, 10);
    rect(0, 0, width, height);
}

```

The problem is that the shapes never fade away completely. The lower the alpha (slower the fade), the brighter the ghost that is left behind. Here’s a sample sketch that illustrates my problem. Click to mouse to create more ellipses.  
Can anybody explain to me why the objects stop fading?

```auto
void setup()
{
  size(500, 500);
  background(0);
  ellipse(width/2, height/2, 200, 200);
}

void draw()
{
  noStroke();
  fill(0, 10);
  rect(0, 0, width, height);
  
  if(mousePressed)
  {
    fill(255);
    ellipse(mouseX, mouseY, 100, 100);
  }
}

```

---

<div class="post-metadata">

**Author:** ![debxyz](https://avatars.discourse-cdn.com/v4/letter/d/58956e/32.png) [@debxyz](https://discourse.processing.org/u/debxyz)\
**Post date:** [March 22, 2020, 2:30am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/2 "2020-03-22T02:30:40Z")

</div>

Hello!  
I ran your code in the Processing IDE and in the [openprocessing.org](http://openprocessing.org) online editor.  
In both cases the ellipses faded completely to black…

---

<div class="post-metadata">

**Author:** ![Tomfoolery](https://avatars.discourse-cdn.com/v4/letter/t/97f17d/32.png) [@Tomfoolery](https://discourse.processing.org/u/Tomfoolery)\
**Post date:** [March 22, 2020, 4:18am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/3 "2020-03-22T04:18:54Z")

</div>

Really??  
That’s super interesting. I just tried on [openprocessing.org](http://openprocessing.org) and still have the same problem. Though I just noticed now that it’s way more apparent on my hdmi monitor than my laptop’s, so maybe the screen has something to do with that.  
This is an image of the issue, if you can’t see the dots, than it must me a monitor thing. I really hope someone can help me with this, I have no idea how to troubleshoot it further.  
 ![ghost dots](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/9/9fe09213f7a70dacb5a9d9b06968f43fbf9fa2ee.png)

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [March 22, 2020, 12:13pm UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/4 "2020-03-22T12:13:26Z")

</div>

Hello,

I can see the circle in the black; you can see this effect better if you invert colors.  
I wrote a snippet of code to plot the color over time; you can see the values in the console.

```auto
void setup()
  {
  size(250, 500);
  background(255);
  noStroke();
  fill(0);
  //rect(0, 0, width, height);
  ellipse(width/2, 3*height/4, 200, 200);
  noStroke();
  }

void draw()
  {
  noStroke();
  //push();
  fill(255, 10); //Try different values here; 1 gives a stragiht line
  rect(0, 250, width, height);
  //pop();
  int col = get(width/2, 3*height/4);
  println(hex(col), (red(col)));
  
  push();
  strokeWeight(2);
  stroke(0);
  point(x, red(col));
  x++;
  if(x >= width) noLoop();
  pop();

  if(mousePressed)
    {
    fill(0);
    ellipse(mouseX, mouseY, 100, 100);
    }
  }

```

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/c/ccc046192e2f2b7f1df87b326fa8b4caaa2865f6.png)

`:)`

---

<div class="post-metadata">

**Author:** ![Tomfoolery](https://avatars.discourse-cdn.com/v4/letter/t/97f17d/32.png) [@Tomfoolery](https://discourse.processing.org/u/Tomfoolery)\
**Post date:** [March 22, 2020, 3:45pm UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/5 "2020-03-22T15:45:15Z")

</div>

Thanks for taking the time to put that together @glv 🙂 It’s a helpful visualization of what’s going on, and after some playing around I found that the fill’s opacity needs to be above 125ish for the get() command to return pure white, which gives me a better understanding of what’s going on.

It occurred to me to see if the issue happens in Photoshop as well, which it does. So this must be an inherent math thing rather than a processing thing. I think I’ll try experimenting with blend modes over opacity when I have time later. I have a feeling the solution’s in there somewhere.

---

<div class="post-metadata">

**Author:** ![Tomfoolery](https://avatars.discourse-cdn.com/v4/letter/t/97f17d/32.png) [@Tomfoolery](https://discourse.processing.org/u/Tomfoolery)\
**Post date:** [March 22, 2020, 5:05pm UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/6 "2020-03-22T17:05:19Z")

</div>

Well, if anybody else has trouble with this down the line, you can get rid of the ghost effect by using blendMode(MULTIPLY).

```auto
  blendMode(MULTIPLY);
  fill(0, 50);
  rect(0, 0 , width, height);

```

---

<div class="post-metadata">

**Author:** ![debxyz](https://avatars.discourse-cdn.com/v4/letter/d/58956e/32.png) [@debxyz](https://discourse.processing.org/u/debxyz)\
**Post date:** [March 22, 2020, 5:26pm UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/7 "2020-03-22T17:26:08Z")

</div>

I wonder if it has to do with the type of screen being viewed on? I am on a mac…

---

<div class="post-metadata">

**Author:** ![philbutrin](https://avatars.discourse-cdn.com/v4/letter/p/7ab992/32.png) [@philbutrin](https://discourse.processing.org/u/philbutrin)\
**Post date:** [March 22, 2020, 9:11pm UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/8 "2020-03-22T21:11:24Z")

</div>

Do you need to reset the blendMode to something else after drawing the rect over the screen? When I use blendMode(MULTIPLY) as shown, nothing else I draw in the program appears on the screen.

---

<div class="post-metadata">

**Author:** ![Tomfoolery](https://avatars.discourse-cdn.com/v4/letter/t/97f17d/32.png) [@Tomfoolery](https://discourse.processing.org/u/Tomfoolery)\
**Post date:** [March 23, 2020, 3:09am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/9 "2020-03-23T03:09:11Z")

</div>

@philbutrin yes, you’ll need to change it back to default. blendMode(BLEND) will do it. You can also use the push/pop methods to revert back to previous settings

```auto
push()
blendMode(MULTIPLY);
fill(0, 10);
rect(0, 0, width, height);
pop();

```

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [March 23, 2020, 3:56am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/10 "2020-03-23T03:56:51Z")

</div>

blendMode(ADD) will also work.

The reason that this happens with repeated use of `blendMode(BLEND)` is, in a nutshell, Zeno’s paradox. See prior discussion with example test sketches and some digging into the math here:

> <https://github.com/processing/processing/issues/4743>
>
> The same thing with 'transparent black'
> How black or white the repainted section becomes is a function of the transparency of the...

---

<div class="post-metadata">

**Author:** ![Tomfoolery](https://avatars.discourse-cdn.com/v4/letter/t/97f17d/32.png) [@Tomfoolery](https://discourse.processing.org/u/Tomfoolery)\
**Post date:** [March 23, 2020, 4:52am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/11 "2020-03-23T04:52:24Z")

</div>

@jeremydouglass Thanks for taking the time to share the math, though I can’t say I understand it. I was under the impression that adding say, pure white with 5 alpha meant that you were adding 5/255 to the canvas until the whole thing became white. If you’re willing to to explain what’s actually going on here I’m super interested in hearing it, but if not I’m at least getting the effect I’m looking for even if I don’t understand what’s going on.

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [March 23, 2020, 5:23am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/12 "2020-03-23T05:23:06Z")

</div>

> [@Tomfoolery](#):
>
> you were adding 5/255 to the canvas until the whole thing became white

That would be true in `blendMode(ADD)`. Then you add 5.  
But with `blendMode(BLEND)` you get `dest * (1 - srcAlpha) + src * (srcAlpha)`.

fill(0, 10) is 10/255 = ~0.039.

So it leaves 96% of a canvas pixel value each time it is applied.

96% of 13 is 12.46, which is saved as an int =12. (canvas pixels are ints). BUT:

96% of 12 is 11.52… which is 12. So a pixel that is at 12, when covered with fill(0, 10), will stay 12. And then 12. And then 12…

Watch it happen in this example sketch – it shrinks to 12, then stays there:

```auto
float dest = 255; // white canvas pixel
int src = 0; // black fill pixel
float srcAlpha = 10.0/255; // black fill alpha channel

for(int i = 0; i<100; i++) {
  print(dest, " | ");
  float result = dest * (1 - srcAlpha) + src * (srcAlpha); // blendMode(BLEND)
  dest = round(result); // results saved as int in original pixel
}

```

12 is the specific resulting value for 10/255, but for different inputs you get different final values (towards white or black) where the final value gets stuck before reaching 0 (or 255).

---

<div class="post-metadata">

**Author:** ![philbutrin](https://avatars.discourse-cdn.com/v4/letter/p/7ab992/32.png) [@philbutrin](https://discourse.processing.org/u/philbutrin)\
**Post date:** [March 23, 2020, 10:53am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/13 "2020-03-23T10:53:43Z")

</div>

Great. Thanks for the reply!

---

<div class="post-metadata">

**Author:** ![Tomfoolery](https://avatars.discourse-cdn.com/v4/letter/t/97f17d/32.png) [@Tomfoolery](https://discourse.processing.org/u/Tomfoolery)\
**Post date:** [March 23, 2020, 1:30pm UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/14 "2020-03-23T13:30:19Z")

</div>

Great explanation, I get it now. Thanks for demystifying that for us 🙂

---

<div class="post-metadata">

**Author:** ![minipif](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/minipif/32/8374_2.png) [@minipif](https://discourse.processing.org/u/minipif)\
**Post date:** [March 26, 2020, 8:57am UTC](https://discourse.processing.org/t/fade-effect-whats-with-the-ghost/18891/15 "2020-03-26T08:57:21Z")

</div>

You can control the pixel values directly with `pixels[]`:

```auto
void setup() {
  size(400, 400);
  
  stroke(#ffffff);
  strokeWeight(8);
}

void draw() {
  line(random(width), random(height), random(width), random(height));
  fade(4);
}

void fade(int amount) {
  loadPixels();
  for (int i = 0; i < pixels.length; i++) {
    int argb = pixels[i];
    int a = (argb >> 24) & 0xFF;
    int r = (argb >> 16) & 0xFF;
    int g = (argb >> 8) & 0xFF;
    int b = argb & 0xFF;
    r = max(0, r - amount);
    g = max(0, g - amount);
    b = max(0, b - amount);
    pixels[i] = (a << 24) | (r << 16) | (g << 8) | b;
  }
  updatePixels();
}

```
