Gamua / Starling-Framework

The Cross Platform Game Engine
http://www.starling-framework.org
Other
2.82k stars 821 forks source link

Render Texture: draw method doesn't render display object with filter if parent is shifted #1088

Open Adolio opened 2 years ago

Adolio commented 2 years ago

Hi Daniel,

Me again 🙄...

I found an issue related to drawing a display object with a filter assigned to it. Apparently the matrix is not correctly computed when the parent (root) is shifted. Happily I have a piece of code to reproduce it easily.

I'm still trying to implement a post-effect stack and this issue is really blocking me because I cannot render my whole scene into a RenderTexture to then apply extra FragmentFilters or a custom MeshStyle.. 😬 (edit: I found a workaround, see next comment)

I hope this is fixable 🤞

Best, Aurélien


Description

When rendering a DisplayObject with a FragmentFilter applied on it in a RenderTexture, the object position is not correct if the parent of the object is shifted.

Code to reproduce

The following code reproduces the issue on my side:

package
{
    import starling.animation.IAnimatable;
    import starling.core.Starling;
    import starling.display.Image;
    import starling.display.Quad;
    import starling.display.Sprite;
    import starling.filters.BlurFilter;
    import starling.filters.GlowFilter;
    import starling.textures.RenderTexture;

    public class PostEffectTest extends Sprite implements IAnimatable
    {
        private var _renderingTexture:RenderTexture;
        private var _renderingImage:Image;
        private var _camera:Sprite
        private var _entity:Quad;

        public function PostEffectTest()
        {
            var offset:Number = 100; // set to 0 and it works as expected

            // camera
            _camera = new Sprite();
            _camera.x = -offset;

            // entity
            _entity = new Quad(100, 100, 0xff0000);
            _entity.alignPivot();
            _entity.x = offset + Starling.current.stage.stageWidth * 0.5;
            _entity.y = Starling.current.stage.stageHeight * 0.5;
            _entity.filter = new GlowFilter(0x00ff00); // remove this line and it works
            _camera.addChild(_entity);

            // render
            _renderingTexture = new RenderTexture(800, 480, false);
            _renderingTexture.clear(); // might prevent Error #3605: Sampler 0 binds an invalid texture. (https://github.com/Gamua/Starling-Framework/issues/1087)
            _renderingImage = new Image(_renderingTexture);
            _renderingImage.filter = new BlurFilter();
            addChild(_renderingImage);

            // animation setup
            Starling.current.juggler.add(this);
        }

        public function advanceTime(passedTime:Number):void
        {
            _entity.rotation += Math.PI * passedTime;

            _renderingTexture.draw(_camera);
            _renderingImage.setRequiresRedraw(); // required to update the image
        }
    }
}

Here is the faulty result with an offset of 100 applied on the camera (-) and the entity (+):

withFilter

If the offset is set to 0 you get the expected result:

withoutOffset

If the GlowFilter applied to the entity is removed then you get the correct result (obviously without the expected filter):

withoutFilter

Adolio commented 2 years ago

I just found a workaround and probably the root cause of this issue 😀

Apparently the transform of the root display object is not took into account when this later object is not added to the stage while drawing (but only for DisplayObjects with filters).

Workaround

addChild(_camera); // adding the drawn object to the stage solves the issue!
_renderingTexture.draw(_camera);
removeChild(_camera); // remove the drawn object to prevent rendering it twice

@PrimaryFeather Is this the intended behavior?

PrimaryFeather commented 2 years ago

Haha, Aurélien, what are you doing to me? This is the worst possible combination to debug, filter plus render texture! 😂

I just tried to debug your sample to get to the root of the issue. It definitely has something to do with the object not being part of the stage, though I haven't been able to exactly put my finger on the problem.

When the current render target is a render texture, the fragment filter logic should replace all stage-related values with those of the render texture, as it effectively becomes the viewport in that case. I think I remember hitting a wall in that area, as my comment in this line shows.

In that case, the only solution would have been a breaking change in the DisplayObject class, which is a no-go, so I decided to postpone this change for Starling 3.0. :wink:

To be honest, I'm not 100% sure it's exactly this issue. I'll try to look into it again with a clear head — getting my mind into this matrix stuff again is not easy. 🤪 But it seems very likely, and that your workaround fixes the problem indicates that it's connected.

At least you've got a workaround now! The other thing you could do instead is to not use a render texture, but instead add a filter to your root object (whatever is "Starling.root") instead. In that case, every object can stay on the stage, and the FragmentFilter class can even optimize the filter bounds and not draw anything that's outside the stage.

However, if that's an alternative depends on what exactly you want to achieve.

MNiceback commented 2 years ago

UNSUBSCRIBE @.*** please.


From: Daniel Sperl @.> Sent: Tuesday, August 3, 2021 2:47 PM To: Gamua/Starling-Framework @.> Cc: Maxime Baudaux @.>; Comment @.> Subject: Re: [Gamua/Starling-Framework] Render Texture: draw method doesn't render display object with filter if parent is shifted (#1088)

Haha, Aurélien, what are you doing to me? This is the worst possible combination to debug, filter plus render texture! 😂

I just tried to debug your sample to get to the root of the issue. It definitely has something to do with the object not being part of the stage, though I haven't been able to exactly put my finger on the problem.

When the current render target is a render texture, the fragment filter logic should replace all stage-related values with those of the render texture, as it effectively becomes the viewport in that case. I think I remember hitting a wall in that area, as my comment in this linehttps://github.com/Gamua/Starling-Framework/blob/ae77db04fade01098b1360d5efed6a2e74a79e17/starling/src/starling/filters/FragmentFilter.as#L205 shows.

In that case, the only solution would have been a breaking change in the DisplayObject class, which is a no-go, so decided postpone this change for Starling 3.0. 😉

To be honest, I'm not 100% sure it's exactly this issue. I'll try to look into it again with a clear head — getting my head into this matrix stuff again is not easy. 🤪 But it seems very likely, and that your workaround fixes the problem indicates that it's connected.

At least you've got a workaround now! The other thing you could do instead is not use a render texture, but instead add a filter to your root object (whatever is "Starling.root") instead. In that case, every object can stay on the stage, and the FragmentFilter class can even optimize the filter bounds and not draw anything that's outside the stage.

However, if that's an alternative depends on what exactly you want to achieve.

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/Gamua/Starling-Framework/issues/1088#issuecomment-891818521, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAVBLWG4TSLCMQVS2KGNODTT27QOFANCNFSM5BNMP57A. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email.

PrimaryFeather commented 2 years ago

Hello Maxime,

you're getting those notification mails from GitHub, so I can't help you with unsubscribing – you probably have to "unstar" the repository or update your GitHub user settings.

Daniel

On 03.08.2021, at 14:49, Maxime Baudaux @.***> wrote:

UNSUBSCRIBE @.*** please.


From: Daniel Sperl @.> Sent: Tuesday, August 3, 2021 2:47 PM To: Gamua/Starling-Framework @.> Cc: Maxime Baudaux @.>; Comment @.> Subject: Re: [Gamua/Starling-Framework] Render Texture: draw method doesn't render display object with filter if parent is shifted (#1088)

Haha, Aurélien, what are you doing to me? This is the worst possible combination to debug, filter plus render texture! 😂

I just tried to debug your sample to get to the root of the issue. It definitely has something to do with the object not being part of the stage, though I haven't been able to exactly put my finger on the problem.

When the current render target is a render texture, the fragment filter logic should replace all stage-related values with those of the render texture, as it effectively becomes the viewport in that case. I think I remember hitting a wall in that area, as my comment in this linehttps://github.com/Gamua/Starling-Framework/blob/ae77db04fade01098b1360d5efed6a2e74a79e17/starling/src/starling/filters/FragmentFilter.as#L205 shows.

In that case, the only solution would have been a breaking change in the DisplayObject class, which is a no-go, so decided postpone this change for Starling 3.0. 😉

To be honest, I'm not 100% sure it's exactly this issue. I'll try to look into it again with a clear head — getting my head into this matrix stuff again is not easy. 🤪 But it seems very likely, and that your workaround fixes the problem indicates that it's connected.

At least you've got a workaround now! The other thing you could do instead is not use a render texture, but instead add a filter to your root object (whatever is "Starling.root") instead. In that case, every object can stay on the stage, and the FragmentFilter class can even optimize the filter bounds and not draw anything that's outside the stage.

However, if that's an alternative depends on what exactly you want to achieve.

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/Gamua/Starling-Framework/issues/1088#issuecomment-891818521, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAVBLWG4TSLCMQVS2KGNODTT27QOFANCNFSM5BNMP57A. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/Gamua/Starling-Framework/issues/1088#issuecomment-891819875, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAEFUE7GEEEA4I7P4RA2H73T27QWRANCNFSM5BNMP57A. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email.

Adrian-S commented 2 years ago

I'm having the same issue, or similar.

When I apply a ColorMatrixFilter on and ImageLoader the image disapears. If I apply it on it's parent it works but has unexpected results (stuff gets moved around).

All gets drawn to a RenderTexture, and workaround did not work for me.

I will probably need to create multiple color textures for this. Is there a way to apply a filter to a texture and get a new texture out of it?

PrimaryFeather commented 2 years ago

When I apply a ColorMatrixFilter on and ImageLoader the image disapears. If I apply it on it's parent it works but has unexpected results (stuff gets moved around).

Did you try adding the filter only in the Event.COMPLETE event handler? Perhaps the filter gets drawn too soon, while there's no texture data available yet?

In any case, here is a simple utility function that allows you apply a filter directly to a texture.

Adrian-S commented 2 years ago

I gave it a 2 seconds timeout where I can see the object rendered corectly, then it's drawn and replaced with the texture.

For me it's a sort of cache where I reduce the number of objects from 35 (up to 80) to just 7. I've allready generated a new texture, but the utility function could help too.

Thank you.

PrimaryFeather commented 2 years ago

I gave it a 2 seconds timeout where I can see the object rendered corectly, then it's drawn and replaced with the texture.

Hm, okay. Sorry for the troubles – this is absolutely something that should work. I hope I'll find the time to take another look at this problem.

For me it's a sort of cache where I reduce the number of objects from 35 (up to 80) to just 7. I've already generated a new texture, but the utility function could help too.

Okay! It's definitely a smart idea to use RenderTextures as a cache to simplify the scene. 👍