davidfig / pixi-cull

a library to visibly cull objects designed to work with pixi.js
MIT License
109 stars 15 forks source link

Do I need to do something special when I resize the window? #4

Closed embeddedt closed 4 years ago

embeddedt commented 4 years ago

I'm using this library, along with pixi-viewport, in an isometric game I'm building. I need to have a lot of tiles so optimizing rendering speed is important to me. I found that pixi-cull was very easy to set up and does exactly what I'm looking for. Great job!

I have run into one issue. When I resize the window, the culling logic's impression of the viewing area seems to be incorrect. It is culling objects when there is no need to.

Capture

I'm not rotating or skewing any sprites, so I don't think it's an incorrect calculation of the tiles' bounding boxes. I also find it weird that this only happens once I resize the window.

Here's the window's onresize handler:

        TileSystem.app.renderer.resize(TileSystem.app.view.clientWidth, TileSystem.app.view.clientHeight);
        this.viewport.resize(TileSystem.app.view.clientWidth, TileSystem.app.view.clientHeight);
        TileSystem.onResize();
        requestAnimationFrame(() => {
            if(this.cull != null)
                this.cull.cull(this.viewport.getVisibleBounds());
        });

I added the requestAnimationFrame on a whim that perhaps bounds calculation is not done until the next frame, but that didn't help.

I also tried the pixi-cull live demo, but when I resize the window, the canvas just gets scaled and the viewport doesn't seem to resize.

I've tried both algorithms; they both have the same symptoms when the window resizes.

Any suggestions? The only workaround I can think of would be for me to disable culling once the window resizes, which will probably make it unusable on mobile devices.

davidfig commented 4 years ago

Hmm...your code looks correct for resize. I'm not sure what the problem is. For me pixi-cull and pixi-viewport work fine on mobile devices and during resize.

I updated the github demo (https://davidfig.github.io/pixi-cull/) so it supports resizing of the window. It seems to work properly. See if it gives you any ideas.

Also, unless your scene is moving, you should only need to call the cull once after the resize.

embeddedt commented 4 years ago

Thanks for updating the demo; that was really useful to work with.

I've finally been able to put a workaround together, but I think there is still an issue somewhere, most likely in my code.

I forgot to mention an important detail: my tiles do change their position and size when the window resizes (where TileSystem.onResize() is called). I discovered that if I turned off that feature (and made them keep their size and position) everything seems to work fine.

After comparing the handling of onresize by your demo and my code, I came up with this quite ugly workaround that fixes the problem, but is very slow.

        TileSystem.tileSize = getTileSize(); /* Changes tiles' size */
        TileSystem.app.renderer.resize(0, 0); /* Probably not necessary, I don't use flex on the canvas */
        this.viewport.resize(TileSystem.app.view.clientWidth, TileSystem.app.view.clientHeight);

        TileSystem.app.renderer.resize(TileSystem.app.view.clientWidth, TileSystem.app.view.clientHeight);

        /* TileSystem.onResize changes tiles' positions */
        TileSystem.onResize().then(() => {
            if(this.cull != null) {
                this.cull.removeList(this.viewport.children); /* Remove all tiles */
                this.cull.addList(this.viewport.children); /* Add all tiles */
                this.cull.cull(this.viewport.getVisibleBounds());
            }
            this.viewport.dirty = true;
        });

This seems to be working, but the culling is now very slow when the window resizes (probably because of the removing/adding of tiles). I tried updateObjects instead of removing and adding the tiles but that produces the same symptoms as the original problem (the wrong tiles are being culled).

As an aside: I've gone back to using the Simple algorithm; is there a particular advantage to using the hash one? I've never dealt with manually culling like this before so my apologies if that's a basic question.

davidfig commented 4 years ago

Ah. I think I figured out your problem. Try setting options.dirtyTest = false.

The default settings is for pixi-cull not to update your objects bounding box during the cull call. (This is probably confusing and I might switch the default.) It's set up to avoid updating the bounding box every frame (since my apps cull every frame since there are lots of moving objects). What I do is add a dirty flag (eg, container.dirty) and update the bounding box only when that flag is set. Updating the bounding box is slow because it calls pixi's getBounds, which recalculates the transforms.

Since you're only calling the cull when you resize, there should be minimal impact on performance, except for resize. Resizes are always slow given all the recalculations going on.

As for simple vs. hash, if you don't have that many objects, simple is fine. Hash is nice because it also helps with collisions. Hash divides the world into boxes and places objects in one (or more) boxes. When checking cull (or collision), you only need to find boxes that intersects the viewport. That lowers the number of box-box intersection checks. Simple works fine up to a certain number of elements; after that hash will be faster.

Hash is super useful when collision testing because you don't need to compare every object against every other object. To check collisions you just compare objects that are in the same box.

embeddedt commented 4 years ago

Thanks! Setting dirtyTest to false seems to have completely fixed all the issues I was having, and I no longer need any hacks.

I appreciate the explanation of how it works internally. Now it's behavior makes a lot more sense. I agree that changing the default or at least adding a note in the README file would help.

Thanks again. I'll close this issue now.