Search code examples
javascriptfiltermaskcreatejsgsap

Mask with Alpha Filter in EaselJS or TweenMax


I'm trying to do a sheen effect passing above of my image and I just want that this effect just should show in the content of my image and not the all container. I been trying it a lot and I can not make working the alphaMaskChannel. I will appreciated if someone can help me and explain me what I'm doing wrong.

This is my example:

var stage = new createjs.Stage("canvas");
createjs.Ticker.addEventListener("tick", tick);

var imgSheen = new createjs.Shape();
var bmp = new createjs.Bitmap("http://upload.wikimedia.org/wikipedia/pt/0/02/Homer_Simpson_2006.png");


imgSheen.graphics.beginLinearGradientFill(['rgba(255,255,255,0)', '#000', 'rgba(255,255,255,0)'], [0, 0.5, 1], 0, 0, 50, 0).drawRect(0, 0, 100, 600);
imgSheen.rotation = 18;

imgSheen.filters = [
          new createjs.AlphaMapFilter(bmp)
        ];
stage.addChild(bmp, imgSheen);

function tick(event) {
    createjs.Tween.get(imgSheen).to({x:300}, 4000);
    stage.update();    
}

Link: https://jsfiddle.net/Dbardaji/ndmzLt1z/


Solution

  • I think I know what you are trying to do, and there are a few steps to get there. Alpha masks are more complex in canvas than something like Animate/Flash, so set up is more difficult. Animating the effect is also difficult.

    Properly applying the filter

    1. The filter you are looking for is AlphaMaskFilter, not AlphaMapFilter. The latter uses a color channel to apply the filter, and not the alpha channel. Also, the filter takes an image, and not a Bitmap.

    2. You should wait until the image loads before applying it to avoid errors, or nothing showing up.

    3. DisplayObjects have to be cached in order to have filters applied. This "freezes" the object, so any time it changes, it has to be re-cached.

    4. In your case, you are applying the filter to "imgSheen", but you should be using the imgSheen as the source. In order to do this, you have to cache the imgSheen instead, pass its cacheCanvas to the AlphaMaskFilter, apply it to the bmp, and then cache the bmp to apply the filter.

    5. Don't add imgSheen to the stage. It is part of the filter applied to the Bitmap, and should not be visible.

    Here is a sample of the above steps: https://jsfiddle.net/lannymcnie/ndmzLt1z/3/

    Key bits:

    imgSheen.cache(0,0,100,400); // Cache the sheen so it can be used in the filter
    bmp.filters = [
        new createjs.AlphaMaskFilter(imgSheen.cacheCanvas) // Use the right filter
    ];
    bmp.cache(0,0,bmp.image.width,bmp.image.height); // Apply the filter
    stage.addChild(bmp); // Don't add imgSheen to the stage
    

    Animating the Effect

    In order to add animation, the position of the filter has to change. This is made difficult because:

    1. You have to re-cache the bitmap any time the filter changes

    2. The way linear bitmap fills work, you can't just change the x position (you have to update the gradient positions, drawRect position, and the cache position. To simplify it, I added a Container, put the gradient in it, and instead cached the Container. This means the imgSheen can move freely, and we can just update the container cache any time.

    3. The cache of the Container and the cache of the filter have to be updated any time it changes.

    I moved the Tween out of the tick method (we just want it to happen one time - not be created each tick), and added a "change" listener to update the caches. Here is an updated demo: https://jsfiddle.net/lannymcnie/ndmzLt1z/4/

    Key bits:

    c = new createjs.Container();
    c.addChild(imgSheen);
    
    createjs.Tween.get(imgSheen, {loop:true}).to({x:200}, 2000, createjs.Ease.quadInOut)
        .on("change", function() { 
            c.cache(0,0,250,400); 
            bmp.cache(0,0,bmp.image.width,bmp.image.height);
        });
    

    Just a heads up that updating a cache every frame is not ideal. It might be better to make a reverse gradient that covers the image, instead of masks it (and blends into the background). You could mask the gradient and image to constrain it to the image size.

    Hope that helps!