Jump to content

Layered Lighting System Using Masks Issue


Recommended Posts

I've been trying to sort this out for a bit. I'll try to keep it simple.

I'm using pixi-layers & pixi v4.

I have Sprites that use a texture (generally png) as a light. This gets added to the stage and assigned to a sorting group. Layering works fine at this point.

Next is ambient lighting, it's also added to the stage at the highest zIndex and assigned to the sorting group so (obviously it renders above everything else).

Next each light has a mask that is based off of the Sprites texture.

This gets added to the ambient lighting container. Herein lies the problem.

The mask in the ambient lighting container, of course renders at the same zIndex that the ambient lighting container is at and not at the zIndex that the light sprite is at.

The mask should render at the same zIndex as the light sprite.

Any suggestions on how to go about this?


Thanks! I've attached an example screenshot of my current results.

As you can see the light sprite renders at the proper zIndex (lets say 3 for example).

The tree renders at zIndex 4 for example.

The mask renders above the tree (which it shouldn't).

Screen Shot 2019-10-24 at 8.55.30 PM.png

Link to comment
Share on other sites

> The mask in the ambient lighting container, of course renders at the same zIndex that the ambient lighting container is at and not at the zIndex that the light sprite is at.

Mask is rendered in "renderer.maskManager.pushMask" operation, in a container that is masked.

Yes, there is a problem with how to make masks with pixi-layers. Fortunately, you have minimal example, right? Please publish it and tell me more info about it.

Two possible outcomes:

1. we find how to adjust pixi-layers logic thus masks works the way you want

2. we find that mask isnt actually needed, instead we need gray version of tree in light layer or something like that

Welcome to the forums! That's a powerful first post.

Edited by ivan.popelyshev
Link to comment
Share on other sites

Thanks for your reply ivan and thanks for the welcome!

I am unable to post the full logic of this as it's tied into a massive project i'm working on, but i've stripped out the steps to get to this point and posted it on fiddle and a code example below to work with. I've also linked to a video of this in action.

Fiddle Link: https://jsfiddle.net/1caoymvs/ (start at around line 754)

Hope this code example is clear! Thanks again.

this.container = new PIXI.Container();
this.container.zIndex = 1;
this.container.sortGroup = new PIXI.display.Group( 0, false );
this.container.sortLayer = new PIXI.display.Layer( this.container.sortGroup );
this.stage.addChild( this.container.sortLayer ); // @stage is an instance of PIXI.display.Stage

this.container.parentGroup = this.container.sortGroup;
this.container.parentLayer = this.container.parentLayer;
this.stage.addChild( this.container );

// The ambient lighting container with mask children
this.ambientOverlay = new PIXI.Sprite( PIXI.Texture.WHITE );
this.ambientOverlay.zIndex = 999999;
this.ambientOverlay.tint = 0x000000;
this.ambientOverlay.width = this.width;
this.ambientOverlay.height = this.height;
this.ambientOverlay.parentGroup = this.container.sortGroup;
this.ambientOverlay.parentLayer = this.container.sortLayer;
this.container.addChild( this.ambientOverlay );

// @theTexture being a cached Texture
this.light = new Sprite_Light( theTexture, this ); // Sprite_Light is a simple extension of PIXI.Sprite ultimately
this.light.zIndex = 2;
this.light.parentGroup = this.container.sortGroup;
this.light.parentLayer = this.container.sortLayer;
this.container.addChild( this.light, this );

    The "tree" is part of a tilemap (think how RPG Maker MV uses pixi-tilemap) that's also added to "container".
    The tilemap is also assigned a parentGroup/parentLayer, the layering of the tilemap works fine.
    So it seems option 1 with a gray version might be expensive
    There are also other "Sprites" on the scene on various layers with textures
    The "texture" used for the light as well as the lights positioning may also be changed during runtime.

window.Sprite_Light = function() {
    this.initialize.apply( this, arguments );

Sprite_Light.prototype = Object.create( Sprite.prototype );

Sprite_Light.prototype.constructor = Sprite_Light;

Sprite_Light.prototype.initialize = function( texture, scene ) {
    Sprite.prototype.initialize.call( this );

    this.texture = new PIXI.Texture( this.texture.baseTexture );

    if ( this.lightMask ) this.removeChild( this.lightMask );

    this.lightMask = new PIXI.Sprite( this.texture );
    this.addChild( this.lightMask );


    this.lightMaskOverlay = new PIXI.Sprite( PIXI.Texture.WHITE );
    this.lightMaskOverlay.mask = this.lightMask;
    scene.ambientOverlay.addChild( this.lightMaskOverlay );
        Here is the problem, adding the mask to @ambientOverlay
        Sprite_Light renders on the correct layer (2), but the mask renders on layer (999999)
        Is it possible for the mask as a child of @ambientOverlay to render in said container but
        follow it's own zIndex so it matches Sprite_Light?


Edited by Nyrion
Link to comment
Share on other sites


stage.ambientOverlay.parentGroup = stage.sortGroup;
stage.ambientOverlay.parentLayer = stage.sortLayer;

you need only one of those. Groups are just the global variables, layer is in current stage.

Theoretically, i can just remove all "Group" mentions from plugin at all and leave only layers. Group is just a handy CONSTANT, you can declare it globally without dependencies to stage.

Link to comment
Share on other sites

OK, now i really dont understand what do you want to do there. Behaviour with zIndex=1 is correct because you have a texture on that sprite, of course it affects somehow, tree itself is rendered above if that zIndex is smaller.

Also, that place 

    this.lightMaskOverlay = new PIXI.Sprite( PIXI.Texture.WHITE );
    this.lightMaskOverlay.mask = this.lightMask;
    scene.ambientOverlay.addChild( this.lightMaskOverlay );

shows that you dont understand what pixi-layers is doing, and why all those layers (groups) exist. Because that code shouldn't exist at all if you use pixi-layers.

Imagine that you dont use pixi-layers at all.

You have a problem - some items you put inside a Character have to be rendered before/after all other elements. For example, Shadows and HPBar.

You first renderer all shadows, then characters, then hpbars. Now we have a problem - when you add a character, you have to create three objects and put them in different containers. Also, if you destroy it, you have to remove shadows and hp too! Also, when oyu move character, you also have to change position of those things!

pixi-layers allows you to put hpbar and shadow inside character but to render them when their parentLayer is rendered. That means , every frame for that layer "_activeChildren" are calculated, you can see the list of temporary children in that field of layer!

In case you dont have direct reference to the layer, for example your architecture is very modular and exporting all those things is pain - you can use "parentGroup" , and group is really a constant in your global module.

How light is done: we have separate layer that has filter on it, that way everything that is rendered inside goes into temp framebuffer, and the result is blended together. Now, we can add a light to character but specify that is actually light with "parentLayer = lightLayer" like here: https://pixijs.io/examples/#/plugin-layers/lighting.js


I think that you dont fully understand that code, or I dont understand your logic. I recommend to write the same small demo but without pixi-layers at all, then i'll show you how to add layers that way you can remove many lines of code. Right now it looks like layers only increase number of lines of code. For that purpose, try to animate position of those trees and move them together with light.

In general, layers plugin is supposed to help automate things you already understand and can do by hand.

Edited by ivan.popelyshev
Link to comment
Share on other sites

Thanks for the response ivan.

I wasn't aware that assigning parentGroup wasn't really needed, i've noted this.

Maybe I don't understand how pixi-layers works or my logic isn't understandable.

Basically, the light sprites render in the correct order. The tree sprites also render in the correct order.

It's the ambient lighting container thats at the highest zIndex that has the problem. If I don't add children (mask from the light sprite's texture) then obviously the lights aren't visible since the ambient lighting container sits above everything. But since the ambient lighting container sits above everything so does all of its children.

I've created a new fiddle, with the pixi-layer stuff stripped out.

**Basically the bottom tree should not be lit by the light.


Edited by Nyrion
Link to comment
Share on other sites

It's the ambient lighting container thats at the highest zIndex that has the problem.

your Light_Sprite is also a sprite with texture and its zIndex change affects the rendering order. Its children are ok :)

Also I like people who are working on that kind of things, because they give me fuel for more changes in pixi-layers. I just look how people solve lighting problems manually , assist with removing masks when its possible (mask is a bit slow thing for many objects), and then compress their vision into new algo for pixi-layers.

That work is actual impovement of good old Flash scene tree. Other renderers just add "displayLists" that cant possibly work with filters/masks or remove hierarchy like phaser3 did, before people asked to bring containers back. Here, we are working on actual improvement of concepts that people love.

Edited by ivan.popelyshev
Link to comment
Share on other sites

I knew this would be a complex problem before I began as I couldn't find anywhere where someone else has done this (at least publicy posted). Do you have any suggestions on how to solve this? The only thing I can think of is to modify pixi-layers to include sub-children sorting of some type. For example...

Say the "ambient lighting container" is at zIndex=999999

pixi-layers should render this at the appropriate zIndex.

But lets also include a property say "considerChildZIndex" for the "ambient lighting container"

And the "ambient lighting containers" children (which are mask Sprites) can also contain a zIndex (that matches the Sprite_Light's zIndex).

So when the sorting is done in pixi-layers it will check for "considerChildZIndex" and if found will check the children of that and render the children in the proper order?

Just thinking out loud, i'm not sure if this is realistic or feasible.

Thanks ivan!

Link to comment
Share on other sites

I still believe its a problem with your sprites order and your usage of masks.

I've specified 

stage.lightForSecondTree.renderable = false;

and now i see that red light is gone completely. Of course it was rendered below the tree, like you specified.

I dont understand the result you want to get :) Again, I remind you that mask is not renderable, it doesnt have order, at all. Its just pushed/popped when its time to render "lightMaskOverlay". Imagine that you have transparent-white version of that mask and you use it as a texture for "lightMaskOverlay", it'll be the same. In fact i can point you how to do it without mask but it requires extra plugins and i dont want to make it more difficult.

Now, I want you to write me here complete order in which things should be rendered, and when do you want to apply the mask. Lets try make pixi scene that way the objects are rendered in order you want. I think that there's something wrong with that order.

Yes, its sometimes difficult to imagine those things in your brain without drawing schemes.

Edited by ivan.popelyshev
Link to comment
Share on other sites

The render order should be:

Tree1, Light_Sprite1, Light_Overlay (masked), Light_Sprite2, Light2_Overlay (masked2), Tree2

The result I want to get is similar to what the video you posted has for lighting.

Global ambient lighting with lights at different layers (notice how the light in that video is underneath the base of the tree) 


Link to comment
Share on other sites

and how do you want to do that if light_overlay should be rendered inside ambient light, which is completely in different framebuffer, that should  be applied after everything else? 

I dont get it whats special about base of the tree compared to the rest of tree

Edited by ivan.popelyshev
Link to comment
Share on other sites

I'm not sure how to do that ?, to get it to render in the proper order.

The base of the tree is not illuminated by the light above it (I was referring to the youtube video you linked to).

Edited by Nyrion
Link to comment
Share on other sites

Yep, it makes sense if you have containers "under tree" and "on tree" :

layer_ground, layer_ambient_ground_light, layer_tree, layer_ambient_top_light.

And you put your stuff in those containers. Yep, two ambient layers ? Now imagine how many sprites you have create per one object and understand why did i make that "layers" plugin. 

So, what to do:

1. try to compose scene with those two trees and ambient lights without pixi-layers

2. then ill help you to use layers for that

3. then we'll introduce sorting, there are several ways, i know short ones.

Hm, why do you actually use pixi-4? Is that Rpgmaker-related? I can help better if you have pixi-5


Edited by ivan.popelyshev
Link to comment
Share on other sites

Also, there's a way to debug. First, without layers: just set "renderable=false" on containers that you dont want to see , leave only one that you are interested about. Remove its blendMode if you have one - now you see output only in particular "layer".

Another way - install https://spector.babylonjs.com/ and press record button (page will be refreshed) then record again when you want to capture single frame. That way you'll see the progress how pixi draws the stage.

For example, I take https://www.pixiplayground.com/#/edit/KwAJycAw0oEQd6_YKbQb0 and record one frame:



You can see extra framebuffers. Also there's a list of webgl commands, and if you try Spector extension on that thing from playground - you'll see pthat pixi is pretty efficient. That's because I enabled batching of those circles with "

PIXI.GraphicsGeometry.BATCHABLE_SIZE = 1000;

Otherwise it could show how every circle was rendered separately.

Yes, its a tool from babylonJS team. We love babylon for that!

Edited by ivan.popelyshev
Link to comment
Share on other sites

The second fiddle I posted is without pixi-layers, will that work for your help?

Yeah, I use v4 as there is a lot of dependency to allow for compatibilty with RPG Maker MV.

Oh thats awesome, thanks for showing me that! 

Link to comment
Share on other sites

Yes, jt worked. Its just not possible to put your light under tree as "ambient", you need extra layer below all the trees.

Two things:

1.you want light1, tree2, light2

2. All lights have to be summed together inseparate framebuffer

Thats a contradiction

Actually there is a way to fix that , we need extra tree sprite in lights! I can explain it tomorrow, i need to sleep

Link to comment
Share on other sites

This makes sense, that is a good suggestion. Awesome, thanks for taking the time!

I considered this before but wasn't sure how to take into account if the position/size/scale/texture/etc of a light changes or other lights that interesect if that makes sense.

Edited by Nyrion
Link to comment
Share on other sites

OK, the idea of how to use one-layer-ambient and at the same time do what you want is :

Put in ambient dark versions of trees. just "sprite.tint=0" in ambient for trees. You might wanna use gray version of trees, in that case you need dark-light tint, and here's the plugin: https://github.com/gameofbombs/pixi-heaven/tree/v4.x - that can also help to remove masks that you use (in case you multiply by transparent light, not black-white one!)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...