[BUG] Dynamic Sprite creation with Blending

Hi,

I am trying to figure out how to dynamically create a sprite with blending. Let me explain what it is I am trying to achieve.

I have a full screen Image I want to use as an overlay. This overlay is a solid black colour and has 70% opacity. This makes my whole game background darker.

Now I want to be able to blend a circle (starting with 0% opacity in centre to 100% opacity on outer) to that overlay before each render loop.

How do I achieve this?

So each update on the overlay node.

  • Copy original full screen black 70% opacity image into node.
  • Blend circle image into black node. I will be using Src Blend ZERO, Dst Blend ONE_MINUS_SRC_ALPHA as my circle is alpha based and it will affectivly clear the area of the black overlay I want to clear out.

Thanks for any help.

So are you trying to create a spotlight effect, such as this (except with fading towards the edges): http://www.jqueryscript.net/images/collective/jQuery%20animations-spotlight.jpg

Unfortunately I believe blending functions are applied to what is about to be rendered and what has been rendered, and the scene is rendered from back-to-front, so you wouldn’t be able to blend the circle and the overlay without first rendering one of them, but when something is rendered it will be added to what has already been rendered, so you won’t be able to blend without also applying it to what has already been rendered. (Placing the overlay and circle behind the scene would render them first and allow blending, but I’m not sure if there is a blending function that you could apply that would affect the rest of the scene properly, as it is possible nodes sitting under other nodes would cause issues, and you would need to set a blending function on all nodes in the scene that need to be affected.)

The easiest solution is to use a RenderTexture. Here is a method I just tested which seems to work:

  • Create your overlay, but retain it rather than adding it to the scene.
  • Create your circle and add it as a child of your overlay.
  • Set the appropriate blending function to the circle. I used SRC: ZERO; DST: SRC ALPHA. ( The blending function needs to be added to the node that is rendered second.)
  • Create a RenderTexture the size of the screen, add it to the scene and center it.
  • After creating the RenderTexture and whenever the circle moves (if it does), use beginWithClear with the RenderTexture, use visit with the overlay, and then use end with the RenderTexture.

Note: I used the C++ version of cocos2d-x, but I’m sure this will work on CocosCreator as well.

Just in case it’s not clear what is happening here: When you visit the overlay, the overlay will be drawn to the RenderTexture and then, because the circle is a child of the overlay, the child will also be draw straight after. The result is the overlay and circle being drawn and blended together, and saved in memory as an image that the RenderTexture uses. Because the RenderTexture has been added to the scene, the image that was created is displayed on top of whatever is under the RenderTexture.

I have been playing around with this however it works in Browser but not getting anything in Simulator.

Not built on device yet to try it on there so not sure.

Below is the code I am using. I start off by creating a black overlay with opacity. I then visit the gradient circle image.

    overlayNode: cc.Node,
    lightMaskBlack: cc.Node,



    if (this.overlayImage === null ) {
        this.overlayImage = new cc.RenderTexture(1080, 1920);
        this.firstRun = true;
    }

    this.lightMaskBlack.opacity = 255;
    this.overlayImage.beginWithClear(0, 0, 0, 255*0.9);
    this.lightMaskBlack.setPosition(400,-400);
    this.lightMaskBlack._sgNode.visit();
    this.overlayImage.end();
    this.overlayImage.setPosition(0, 0);
    this.lightMaskBlack.opacity = 0;
    
    var spriteComp = this.overlayNode.getComponent("cc.Sprite");
    spriteComp.node.opacity = 255;
    if(this.firstRun)
        spriteComp.spriteFrame = new cc.SpriteFrame(this.overlayImage._texture);
    else
        spriteComp.spriteFrame._texture = this.overlayImage._texture;
    spriteComp.sizeMode = cc.Sprite.SizeMode.RAW;
    spriteComp.node.setPosition(cc.p(200,-100));
    spriteComp.node.anchorX = 0.5;
    spriteComp.node.anchorY = 0.5;
    spriteComp.
    this.firstRun = false;

I tried this out and am getting the same issue: RenderTexture texture appears in browser, but not in simulator. Unfortunately I haven’t used Creator very much, so I’m not sure how to proceed from here.

This is a real pain as the whole game design I was working on is based on lights and only way to create is using this method. I must admit it does look good when working in browser :slight_smile: .

Could one of the devs respond to this please and explain how I can do this type of thing on devices.

Thanks

Can no one honestly answer this?