Use multiple masks on a render texture?

Hello everybody, and a happy new year!

With the help of this tutorial I use a render texture to simulate a fog of war which also hides the layers below (I highlight this because this is the reason I don’t simply use WebGL Light2D pipeline), and a bitmap mask to simulate a light source.

Here is a screenshot to give an idea of the result (you can see circled in red a character that is hard to see because he is on the edge of the light source. If he were outside the light, he would be invisible) :

screenshot

(rpg maker XP assets FTW :upside_down_face:)

Here is the gist of the code I use:

code
// the Fog of War render texture
const FoW_texture = this.add.renderTexture( 0, 0, 2000, 2000 );
FoW_texture.fill( 0x000000, 1 );

// the ground layer
const ground_layer = map.createLayer( "ground", tileset );

// the render texture replicates the ground layer to overlay it
FoW_texture.draw( ground_layer ); 

// color the render texture to simulate darkness
FoW_texture.setTint( 0x0a2948 );

// creating a "vision mask"
const vision_mask = this.make.image({
	x: 0,
	y: 0,
	key: 'vision_mask',
	add: false
});

// adding the vision mask to the render texture
FoW_texture.mask = new Phaser.Display.Masks.BitmapMask( this, vision_mask );

I’m very happy with the result, but I was wondering now how to simulate other light sources, since the render texture can only have one mask.

I see 3 possible ways, but they all come with drawbacks I cannot solve :

  • Instead of having one single large render texture for the whole map, I could have several render textures for smaller “regions” of the subdivided map, allowing me to use more than one mask. But then how to manage multiple light sources in a same “region”?

  • I could use in complement with the render texture the Light2D pipeline of WebGL, but it would be hidden under the render texture (or lighting the render texture and its blueish tint which would look weird.

  • finally I could completely change the way I’m doing fog of war and only use Light2D (where it is easy to have several light sources) and change the opacity of sprites according to the distance of the light sources to simulate the fog of war effect. If this is my last solution I will give it a try but it feels a bit over complicated since the render texture and mask worked so well.

I thank anybody taking the time to read this message and wish to all a very happy new year!
Cheers :slight_smile:

I think you would use a second render texture as the bitmap mask source and then draw vision_mask (or other mask textures) on it.

Wow I actually never thought of using a render texture to be another render texture’s mask…
I’ll need a few hours to try this, I will edit my post to report the result. Thank you very much for your answer!

You can also put images in a container and then use the container as the single mask.

4 Likes

smjn thank you so much!

I ended up trying smjn’s solution and it worked wonders. I’m sure samme’s solution would work too but to be honest I’m not very comfortable with texture, so I chose to work with containers.

Here are 2 screenshots of the result as a thank you:

First implementation was a little rough around the edges:

But by tweaking it a bit it works really well, and adding light sources is really simple:

If anyone has the same problem as I have, here is what I changed from the code posted above:

code
// the beginning of the code is the same as above

// lights mask as a container for all light sources in the game
this.lights_mask = this.make.container(0, 0);

// vision mask
const vision_mask = this.make.image({
    x: 0,
    y: 0,
    key: 'vision_mask',
    add: false
});

// campfire mask
const campfire_mask = this.make.image({
    x: 200,
    y: 200,
    key: 'campfire_mask',
    add: false,
});

// adding the images to the container
this.lights_mask.add( [ vision_mask, campfire_mask ] );

// now this is the important line I did not expect: 
// the lights container was being drawn into the scene (even though I used "make" and not "add")
this.lights_mask.setVisible(false);

// adding the lights mask to the render texture
FoW_texture.mask = new Phaser.Display.Masks.BitmapMask( this, this.lights_mask );

I hope this can help others with a similar issue. Thank you again and have a great day!

2 Likes

I know smjn solved this, but your implementation saved my ass,I was trying to extend and override whatever class (layerMap as any).setMask was calling, but this thread totally helped me a lot. THANK YOU!!!