phaser icon indicating copy to clipboard operation
phaser copied to clipboard

Depth sorting and rendering optimizations

Open JernejHabjan opened this issue 3 years ago • 1 comments

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. image

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: image

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: image 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?

JernejHabjan avatar Sep 08 '22 15:09 JernejHabjan

You should probably cull objects outside the camera viewport (toggling visible). Phaser doesn't do this itself.

samme avatar Sep 08 '22 16:09 samme

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 avatar Sep 21 '22 16:09 photonstorm

@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)

JernejHabjan avatar Sep 22 '22 19:09 JernejHabjan