phaser
phaser copied to clipboard
Depth sorting and rendering optimizations
Version
- Phaser Version: 3.55.2
- Operating system: Windows 11 (OS build 22000.856)
- Browser: Chrome Version 105.0.5195.102 (Official Build) (64-bit)
Description
Hello, I've discovered that depth sorting is running slow when rendering large number of sprites. Situation doesn't improve if sprite is not on the screen.
Depth sorting:
I've first seen this issue when running this game.

I've confirmed this also with following example: http://labs.phaser.io/view.html?src=src/depth%20sorting/Depth%20Sorting.js&v=3.55.2
- Steps:
- Increased for loop from 2000 to 20_000
The performance drops because of depth sorting:

Performance of stable sort may be the problem here. I've "updated" the depthSort function like this:
if (this.sortChildrenFlag)
{
StableSort = (list, fn) => list.sort(fn); // note this override with native JS fn
StableSort(this.list, this.sortByDepth);
this.sortChildrenFlag = false;
}
And results:
Results look much better, but sorting may not be correct - right?
Is there a way we could improve this StableSort? It seems that JS sort is stable since ECMA 2019, and twitter post with example
Rendering:
I've also updated same example with for loop like this
for (let i = 0; i < 20000; i++)
{
const image = this.add.image(100 + Math.random() * 6000, 100 + Math.random() * 4000, 'atlas', 'veg0' + Math.floor(1 + Math.random() * 9));
image.depth = image.y;
}
Note that many of sprites won't be visible in camera, so they wouldn't need to be rendered - right?
But by checking renderer function, I see that visibleChildren count doesn't change, whether all sprites are visible on screen or not:
var visibleChildren = this.getVisibleChildren(displayList.getChildren(), camera);
// visibleChildren.length -> this returns 20003
Is there a way these sprites can be occluded?
I am just trying to create new isometric RTS game, where medium-sized grid can be used, and is only partially visible in the camera. So in this case, I have issues with depth sorting slowing down the game, plus renderer taking all sprites into account, and not only ones visible on camera. Is there a way I can bypass these issues somehow?
You should probably cull objects outside the camera viewport (toggling visible). Phaser doesn't do this itself.
Ok, please test the new StableSort I've put into the master branch (you'll need to do a Beta 11 build to get it, npm run dist will create that) - as for camera occlusion, that is out of scope for the v3 renderer, so you'll need to figure out a way to do this for your use-case I'm afraid.
@photonstorm fyi
For repo Izowave this greatly improves performance:
v3.55 avg depth sort: 95ms (on 200 tile width* 200 tile height map)
v3.6 beta 11 (self-built) avg depth sort: 20.8ms (on 200 tile width* 200 tile height map)