phaser3-rex-notes icon indicating copy to clipboard operation
phaser3-rex-notes copied to clipboard

Drop Shadow pipeline broken in Phaser 3.70

Open LaP0573 opened this issue 9 months ago • 10 comments

Updated Phaser to 3.70, as well as rex plugin to 1.60.7, and enabling the Drop Shadow pipeline on a game object leads to odd flickering of the resolution.

Here is an example, moving before and after applying the pipeline (the black line has the pipeline applied to it):

https://github.com/rexrainbow/phaser3-rex-notes/assets/9264791/90fee911-bcd1-4504-a84c-fff363e3bfb3

LaP0573 avatar Nov 22 '23 16:11 LaP0573

Can't reproduce this case.

Here is my test case :

  • Click any position inside background image to move sprite
  • Apply drop shadow post-fx effect when moving start
  • Remove drop shadow post-fx effect when moving stop (reach to target position)

Running on chrome, no flickering occurs.

rexrainbow avatar Nov 23 '23 02:11 rexrainbow

Hey @LaP0573 , hey @rexrainbow ,

Interesting! I'm facing the exact same issue is Maxime on a very similar project (hello Gather friends!)

Capture vidéo du 2023-11-24 15-21-07.webm

For me, it is the "rexOutlinePipeline" that makes this error.

We are initializing the plugin a bit differently (from the Game config) this way:

https://github.com/workadventure/workadventure/blob/95b5f3ed8c329997c5d3f081b9655f6cd75c0daf/play/src/svelte.ts#L154

Could it be related? (also, we are using the last tagged version of rex plugin which seems to be different from the one used in the Codepen that is not yet tagged)

moufmouf avatar Nov 24 '23 14:11 moufmouf

@moufmouf Can't reproduce your case neither. ( my test code, it has camera scrolling ).

rexrainbow avatar Nov 24 '23 16:11 rexrainbow

Mmmh very odd, one detail is that we're applying the shader to Phaser.GameObject.Line objects (which @moufmouf is not so I'm unsure it's related, but figured I'd point it out just in case)

LaP0573 avatar Nov 24 '23 16:11 LaP0573

Hey @rexrainbow ,

Thanks a lot for being so reactive, you are awesome.

Looking at your example, I can actually reproduce the issue sometimes. It does look exactly the same but on the first click to move the object, there seems to be a single frame with glitches in it.

See:

Capture vidéo du 2023-11-24 17-40-44.webm

(the glitch really happens only on the first frame in your example but happens all over the place on our side)

Also, I noticed this happens in Chrome, but not in Firefox (though in Firefox, the effect seems to fail silently sometimes)

I'd be happy to help debug this further, but I'm not sure where to look...

moufmouf avatar Nov 24 '23 16:11 moufmouf

Mmmh very odd, one detail is that we're applying the shader to Phaser.GameObject.Line objects (which @moufmouf is not so I'm unsure it's related, but figured I'd point it out just in case)

Can't reproduce by Line game object neither. Tested on

  • os : window 11
  • browser : chrome, firefox

rexrainbow avatar Nov 25 '23 03:11 rexrainbow

@moufmouf I still can't reproduce that glitch bug in my site.

Here is a shadow effect by built-in shadow effect (gameObject.postFX.addShadow(...)), any click to move this game object. Could you check the render result in your environment?

rexrainbow avatar Nov 25 '23 04:11 rexrainbow

Hey @rexrainbow ,

Thanks a lot for being so reactive, you are awesome.

Looking at your example, I can actually reproduce the issue sometimes. It does look exactly the same but on the first click to move the object, there seems to be a single frame with glitches in it.

See:

Capture.video.du.2023-11-24.17-40-44.webm (the glitch really happens only on the first frame in your example but happens all over the place on our side)

Also, I noticed this happens in Chrome, but not in Firefox (though in Firefox, the effect seems to fail silently sometimes)

I'd be happy to help debug this further, but I'm not sure where to look...

I encountered the same glitches issue.It seems that the first frame after adding a postfx will be randomly painted. Temporally fixed by overriding the postBatch method of the PostFXPipeline class:

Phaser.Renderer.WebGL.Pipelines.PostFXPipeline.prototype.postBatch = function(gameObject) {
  if (!this.hasBooted) {
    this.bootFX();
  } else {
    this.onDraw(this.currentRenderTarget);
  }
  //
  this.onPostBatch(gameObject);
  return this;
};

tongliang999 avatar Nov 27 '23 03:11 tongliang999

@tongliang999 The original logic of postBatch method is

    postBatch: function (gameObject)
    {
        if (!this.hasBooted)
        {
            this.bootFX();
        }

        this.onDraw(this.currentRenderTarget);

        this.onPostBatch(gameObject);

        return this;
    },

It seems a bug in phaser3 engine. In your patch logic, onDraw method won't call if not hasBooted. Because that I can't reproduce the glitch rendering result, I can't open an issue for this case on phase3's repo.

rexrainbow avatar Nov 27 '23 04:11 rexrainbow

Hey @tongliang999 ,

You are right, it is indeed only the first frame after adding a Postfx that has the issue. Because of pretty hard core optimizations I do to avoid useless rendering, it is more visible in my code than elsewhere (I'm stopping the rendering if nothing moves). If I disable those optimizations, I see exactly what you see: just after adding an effect, the first frame has a random glitch.

I managed to make it obvious in the codepen below: on each frame, I either set up the Postfx plugin or remove it.

https://codepen.io/moufmouf/pen/abXjYRV

It definitely looks like a bug in Phaser 3.

moufmouf avatar Nov 27 '23 22:11 moufmouf

@tongliang999 The original logic of postBatch method is

    postBatch: function (gameObject)
    {
        if (!this.hasBooted)
        {
            this.bootFX();
        }

        this.onDraw(this.currentRenderTarget);

        this.onPostBatch(gameObject);

        return this;
    },

It seems a bug in phaser3 engine. In your patch logic, onDraw method won't call if not hasBooted. Because that I can't reproduce the glitch rendering result, I can't open an issue for this case on phase3's repo.

The problem is that the bootFX method does everything that the pipeline needs in order for onDraw to work. So the logic is correct if we assume that WebGLPipeline.boot does indeed do all that we need to render, which I believe it does - this is likely why we don't see this manifest on desktops. However, this patch introduces an artificial frame skip. Perhaps something in the boot process it taking longer than a frame to occur, which is why on the second pass, everything is ok.

I can't see a reason to modify postBatch (I don't think it's the root of the issue), but equally it won't break anything either and will still carry on working on desktops, so we can give it a try in v3.80.

photonstorm avatar Jan 31 '24 20:01 photonstorm

I can confirm your fix works.

Also: the issue happened not only on mobile, but also on desktop in my case (in Chrome only).

:100: I'm so happy I'll finally be able to upgrade Phaser and get the nice features of 3.70!

moufmouf avatar Jan 31 '24 20:01 moufmouf

@tongliang999 The original logic of postBatch method is

    postBatch: function (gameObject)
    {
        if (!this.hasBooted)
        {
            this.bootFX();
        }

        this.onDraw(this.currentRenderTarget);

        this.onPostBatch(gameObject);

        return this;
    },

It seems a bug in phaser3 engine. In your patch logic, onDraw method won't call if not hasBooted. Because that I can't reproduce the glitch rendering result, I can't open an issue for this case on phase3's repo.

The problem is that the bootFX method does everything that the pipeline needs in order for onDraw to work. So the logic is correct if we assume that WebGLPipeline.boot does indeed do all that we need to render, which I believe it does - this is likely why we don't see this manifest on desktops. However, this patch introduces an artificial frame skip. Perhaps something in the boot process it taking longer than a frame to occur, which is why on the second pass, everything is ok.

I can't see a reason to modify postBatch (I don't think it's the root of the issue), but equally it won't break anything either and will still carry on working on desktops, so we can give it a try in v3.80.

@photonstorm Thanks for your reply. After some deep diving in the source code, I have found that not invoking this.currentRenderTarget.bind() is the cause of the first frame glitch.

In the normal run,currentRenderTarget.bind() is called in WebGLPipeline.preBatch. Due to delayed call of bootFx (in PostFXPipeline.postBatch), currentRenderTarget.bind() is not called before drawing the first frame.

I fix this by adding this.currentRenderTarget.bind() after this.bootFx(), it wokrs well on desktop chrome. And it wont introduce any frame skip.

postBatch: function (gameObject)
    {
        if (!this.hasBooted)
        {
            this.bootFX();

            if (this.currentRenderTarget)
            {
                this.currentRenderTarget.bind();
            }
        }

        this.onDraw(this.currentRenderTarget);

        this.onPostBatch(gameObject);

        return this;
    },

tongliang999 avatar Feb 02 '24 07:02 tongliang999

Hey @tongliang999

Whoa, so cool! You nailed it. :heart: I took the liberty to open a PR with your solution here: https://github.com/phaserjs/phaser/pull/6728

@photonstorm, hope can merge this before 3.80! :+1:

moufmouf avatar Feb 02 '24 15:02 moufmouf