Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGL: RenderTexture frames do not render correctly #6057

Closed
andymikulski opened this issue Mar 29, 2022 · 6 comments
Closed

WebGL: RenderTexture frames do not render correctly #6057

andymikulski opened this issue Mar 29, 2022 · 6 comments

Comments

@andymikulski
Copy link
Contributor

andymikulski commented Mar 29, 2022

Version

  • Phaser Version: 3.55, 3.6-beta4
  • Operating system: Windows (but also probably OSX)
  • Browser: Chrome, FF, etc

Description

Adding and referencing frames on a RenderTexture produces visual errors, depending on how that RT frame is rendered. This only occurs in WebGL mode.

The following demonstrates the expected behavior, using Canvas mode. Each quadrant/square is a separate frame on the original render texture.
Canvas

The following demonstrates the exact same code, but in WebGL mode:
WebGL

With some fiddling, it's apparent that there is some issue with Y-flipping; If I adjust the Y-coords of the frames*, I'm able to get some frames to render - albeit incorrectly flipped:
* ex: rt.texture.add('my-frame', 0, x, y, frameWidth, textureHeight - frameHeight); - Note the textureHeight - adjustment

WebGL + semi-Y-flipped frames

I believe there are two issues at hand here (based on my current understanding of the Phaser codebase):

  • Frames registered on RenderTextures need to be Y-Flipped
  • Certain rendering objects need to account for Y-flipped textures

Example Test Code

This codepen reproduces this issue - note the USE_WEBGL flag up top to easily change the current rendering mode.

https://codepen.io/andymikulski/pen/oNoyBGy

The gist, in psuedocode, is really:

const rt = this.add.renderTexture(...);
drawStuffToRT(rt);
rt.saveTexture('my-texture');
rt.texture.add('my-frame', frameX, frameY, frameWidth, frameHeight);

this.add.image(x, y, 'my-texture', 'my-frame'); // Renders upside down - or not at all

Additional Information

I have dug around the code and noticed that checking if a texture is a glTexture and y-flipping accordingly seems to work, but this requires touching MultiPipeline, Blitter, etc., and I wonder if there is a more 'central' fix available.

I'm happy to work on these solutions, but I wanted to get some sort of input before putting in the effort! Thank you!

@andymikulski andymikulski changed the title WebGL: RenderTexture frames do not work correctly WebGL: RenderTexture frames do not render correctly Mar 29, 2022
@samme
Copy link
Contributor

samme commented Mar 30, 2022

May be #6017

@photonstorm
Copy link
Collaborator

Have spent quite a while on this and tested and ruled out the following approaches so far:

1 - Using the WebGL pixelStorei flag to enable FLIP_Y. Frustratingly, this works fine, but you cannot toggle it for a single texture. Once you disable it again, it remains off. I was hoping it would only be in effect when you upload the texture to the GPU, but sadly that doesn't appear to be the case.

2 - Manipulating the UVs during rendering (i.e. in the pipelines). This is possible, but in testing, it conflicted with the 'crop' feature (essentially breaking it entirely). So it could maybe be used as an edge-case, but it also feels wrong because of the cost of doing this literally every single frame, for every single sprite using the RT as its texture.

3 - Inverting the Frame coordinates when adding a frame to a Texture. I'm in two minds over this approach. It works quite well but is illogical and also suffers from being inconsistent between Canvas and WebGL (i.e. reading back a Frame coordinates between the two would be opposite values). On the plus side, it's a one-time solution, so you don't need to do it during rendering.

Another approach I'm considering, but haven't yet tested, is simply letting you flag a RenderTexture as being "not used for display", i.e. you cannot add the Render Texture Game Object itself to the display list. If we do this, then anything drawn to the RT can be drawn inversed, which solves everything and doesn't require inverted Frame coordinates. Because if the base Render Texture is 'upside down', then any Sprite using a Frame from it will just work perfectly from the get go. I think I'll have to try this next. Thinking about it more, as I write this, it could be possible to still display the RT in the game, but have it flipped when it is rendered.

@mesposito-gather
Copy link

@photonstorm Do you have any update on the timeline for a fix for this issue? Thanks!

@photonstorm
Copy link
Collaborator

Spent some more time on this today - and getting close to a fix. Just trying to make it universal, which isn't easy.

@photonstorm
Copy link
Collaborator

photonstorm commented May 30, 2022

Ok, a fix for this is now in the master branch. Use it as follows:

        const origin = this.add.renderTexture(0, 0, 256, 256).setIsSpriteTexture(true);

        origin.draw('mario', 0, 0);

        origin.saveTexture('test-texture');

@photonstorm
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants