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

SpriteFrame rect offset changing on device, with textures exported from TexturePacker. #12847

Open
UKDeveloper99 opened this Issue Jul 14, 2015 · 37 comments

Comments

Projects
None yet
7 participants
@UKDeveloper99
Copy link

UKDeveloper99 commented Jul 14, 2015

I encountered this problem when I started cutting the level in my game in to smaller peices. I am using a sprite atlas exported from TexturePacker. If I move my Cocos2d::Camera (orthographic) in the Y axis the rect for each sprite frame appears to be changing its offset 1 by pixel. It doesn't happen consistently every frame, but maybe every 4-5 frames.
There is a visible offset of the spriteframe and I know the rect is changing because I can see the first line of pixels from the frame above that particular frame in the sprite atlas is getting drawn. I've tried every option in TexturePacker and I'm convinced that's not the problem. I'm 99% it's something going wrong in the Cocos2D-x engine.

It should be fairly simple to reproduce, export a texture pack (sprite atlas) with a few images. Run it on a device, I used iPhone 4S. Then move the camera every frame on the y-axis, I moved it up (+0.1f). I have also tested it on an Android device (Samsung Galaxy Tab 4 10.1) and it still happens.

It's worth mentioning the problem appears to go away if running on the iOS simulator or in Win32, hopefully that may help to fix it.

It's also worth mentioning that the problem appears to happen rather sporadically, i.e. it has no set pattern. My first thought was floating point innacuracies in the shader or something.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 14, 2015

Oh I forgot to mention, it's much easier to see visually if you set the background clear colour to red or white. It's also easier to see the problem if you disabled anti aliasing.
sprite->getTexture()->setAliasTexParameters();

Don't misunderstand the cause however, the problem still exists with anti aliasing and no glclearcolour enabled.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 14, 2015

Thought I'd add a few more comments on this problem. Here's a couple of things about reproducing the bug, make sure to move the camera up or down on the Y-axis, problem doesn't appear on the x-axis movement (this may give clues to fixing it). Make sure to move the camera by 0.05f every frame, this made the bug most noticeable for me, I think it's because this slow movement allows you to see exactly when the sprite gets redrawn at the next line of pixels. Make sure to disable anti aliasing on the sprite frames so the pixel edges are clean.

It's the top edge of pixels from the frame directly above in the sprite atlas that are drawn, so the sprite frame you test needs to have another frame above it. It's like the rect is offsetting by 1 pixel higher each frame then correcting itself.

Another thing, how does the anti aliasing work in cocos? Maybe when you apply anti alias to a sprite frame wouldn't it mix in pixels from other sprite frames outside the sprite frame. I know extrude in texture packing software can solve these problems to an extent.

Hope this helps.

@pandamicro pandamicro added this to the unconfirmed milestone Jul 15, 2015

@pandamicro

This comment has been minimized.

Copy link
Member

pandamicro commented Jul 15, 2015

Thank you for the detailed explanation, we will check this issue later

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 15, 2015

@pandamicro let me know if you need my help.

@slackmoehrle

This comment has been minimized.

Copy link
Contributor

slackmoehrle commented Jul 15, 2015

@pandamicro, @UKDeveloper99 is working on a very tight deadline for a large scale Cocos2d-x game. If we could see about resolving this as soon as makes sense, I think he would appreciate it very much :-)

@fusijie

This comment has been minimized.

Copy link
Member

fusijie commented Jul 16, 2015

@UKDeveloper99 I I almost understand the problem. but could you please provide me some reproduce codes and resource to avoid my misunderstanding test case. Thank you.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 16, 2015

@fusijie Sure I'll put something together.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 16, 2015

Hi @pandamicro @fusijie @ricardoquesada

I put together a small test case using the hello world example project. I used Cocos2D-x v3.4 final from the cocos store, but I'll try later with the newer versions, I have a feeling the bug will still be there however.

Here is the test project, all the code is the in the helloworldscene class.
https://drive.google.com/file/d/0BzImXAeK77t4Z2dCNEZ4X0d4SHM/view?usp=sharing
I packed the sprite atlas separately as well as in the project resources folder for your convenience.
https://drive.google.com/file/d/0BzImXAeK77t4T3FuNjJjWjA0ZVE/view?usp=sharing

Couple more notes: I had a bit of a problem recreating it first, it seems the camera positions and sprite positions make a difference.

@fusijie

This comment has been minimized.

Copy link
Member

fusijie commented Jul 17, 2015

@UKDeveloper99 Thanks for your detailed description and code. I have reproduced this issue and found that the cause may be the texture coordinates. Cocos2d-x provide a precompiled macro CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL to use 99% of the texture. You can enable it in the base/ccConfig.h.

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 18, 2015

@fusijie Does the CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL fix the issue?

IIRC, I added CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL in cocos2d-iphone to prevent some bugs with textures. But actually it was fixing the bugs but it worked ok for some textures.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 20, 2015

@fusijie @ricardoquesada I was aware of CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL, however a lot of my research indicated that this option was essentially a hack fix. it's also worth mentionining that there is visual stretching and shrinking of the textures. It really makes the visual quality poor.

I don't think this can realistically be considered as a fix. I really think this issue needs revisiting and looking at some alternative options, judging by the amount of forum posts over the past 5 years it seems to have been a problem that has plagued developers for a while.

AFAIK there is another hacky solution, you can also avoid the problem occuring by rounding sub pixel coordinates, but this means all coordinates, including parent nodes etc. And I don't think this works when anything is scaled. So yeah, someone brave want to have a look in to a proper fix for this?

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 20, 2015

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 20, 2015

That does mention about the float precision in the shader, I haven't tried that yet, but it seems like a more sensible fix. Is there any big performance implications to having high precision floats in the shader?

Edit: seems it does have a noticeable performance hit on some lower end devices.

@UKDeveloper99

This comment has been minimized.

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 20, 2015

@UKDeveloper99 absolutely... that's why I was surprised that CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL fixed the issue.

@pandamicro @fusijie could you please check this issue again with the info posted by @UKDeveloper99 ? Thanks.

@pandamicro

This comment has been minimized.

Copy link
Member

pandamicro commented Jul 21, 2015

Ok, @fusijie is checking it

@fusijie

This comment has been minimized.

Copy link
Member

fusijie commented Jul 21, 2015

@UKDeveloper99 @ricardoquesada I have refined the test case on my branch. There are some similar issues happened and people either enable CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL or setAntiAliasTexParameters() (implemented by use GL_LINEAR Filtering mode internally) to cover it, but it seems as hack fix. I have not found the solution now, but I want to update my research by now.

I removed camera, and just moving the sprite per frame.

Contrast Tests

  • Test1: Separate, single image. Nothing unusual.
  • Test2: SpriteFrame: levelone_pack_complete1.plist/png
    • Packing the single image by TexturePacker. the origin size is 250 * 30, but output size is 254 * 34, the four direction edge have 2 transparent pixels.
      2015-07-21 17 23 44
    • Run the test, we can see the flash line between two rectangle.
    • Log the vertices position info(after transformed), which is the same as separate image. so, the vertices position is not the cause.
    • But notice that now the texture coordinate is not from 0 to 1.
  • Test3: SpriteFrame: levelone_pack_complete2.plist/png
    • I copied the Test2 png&plist, removed the four direction edge's 2 transparent pixels and modified corresponding plist info(You can change the border padding setting of TexturePacker also). Now the size of png is 250 * 30.
      2015-07-21 17 24 22
    • Run the test, the flash line disappeared.
    • Now the texture coordinate is from 0 to 1 again.
  • Test4: SpriteFrame: levelone_pack_complete3.plist/png
    • I copied the Test2 png&plist, change the four direction edge's 2 transparent pixels to white color.
      2015-07-21 17 25 00
    • Run the test, we can see the white flash line between two rectangle.
    • Notice that now the texture coordinate is not from 0 to 1.
    • So It seems that texture sampler precision deviation issue.

Other Tests

  • Test1: SpriteFrame: levelone_pack_complete4.plist/png
    • Use POT. but there is no improvement.
  • Test2: Improve precision-qualifier
    • replace mediump with highp. but there is no improvement.
  • Test3: Log the texture coordinate.
    • The four vertices' texture coordinate is constant.
      Any thoughts?
@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 21, 2015

@fusijie A couple of things, I'm fairly sure you can't reproduce the issue if the single image occupies the entire texture pack. It's something to do with the texture coordinates that are < 1 and > 0 I think.

Also if this was the case then a regular sprite would also have the same issue.

I think CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL just masks the issue, because when the flash line appears the texture is stretching to fill that area (by 1 pixel) and then it returns to it's original size. It does this over and over.

It's like the rect size (of the frame) is deviating when the flash line appears.

Just my thoughts.

Maybe @ricardoquesada has some ideas.

@fusijie

This comment has been minimized.

Copy link
Member

fusijie commented Jul 21, 2015

@UKDeveloper99 yes, you are right, but Test2 and Test4 both have a 2 pixels padding, and Test3 just as a contrast test. No matter CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL or setAntiAliasTexParameters only to cover the issue. Sorry for my poor English...

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 21, 2015

@fusijie Your English is fine :) Hmm unless I was sat trying to fix the issue myself I'm not sure what to suggest. Can you look at some more things in the debugger. See if the sprite frame rect is changing somewhere maybe?

Also I remember making a test with 0 padding and several frames and I was still experiencing the issue. I don't think the padding makes a difference.

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 21, 2015

@fusijie Please, create a test case that reproduces this bug, call it "Bug #12847" and send a Pull Request with the test case.
If you cannot fix it, I'll take a look at it.
thanks

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 22, 2015

@fusijie One more thing. Please, make sure to add the test in the "cpp-tests" -> "bugs" section.
Thanks!

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 22, 2015

@fusijie thanks. I'm working on the bug now.

@ricardoquesada ricardoquesada modified the milestones: v3.8, unconfirmed Jul 22, 2015

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 22, 2015

I haven't fixed the bug, and I'm not sure what is the best strategy to fix it yet.

I continued with @fusijie 's test and replaced the top line with Pink and the bottom line with Yellow.
The example from the left is using simple sprites. The example from the right is using SpriteFrame.
As you can see the example from the left doesn't show the "gap", the background red line, because it is drawing the top line (Pink) twice.
And the example from the left has the gap because it is not drawing the top line twice.

img_3436

So, my suggestions for the moment are:

  • If you are not doing a 3d game, set the Director projection to Director::Projection::_2D
  • Use the extrude option in TexturePacker with a 2 pixel pad.

More info about this bug:

  • This happens on regular sprites as well... sprites that use the whole texture (0,1), but it less noticeable
  • Yes, the bug is related to subpixeling, but turning on highp won't necessarily fix all the problems
  • CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL might solve it, but it is not the real fix.
@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 22, 2015

Pull Request that improves that test case: https://github.com/cocos2d/cocos2d-x/pull/12964/files

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 23, 2015

@ricardoquesada interesting, I have seen some posts on forums about setting the projection to 2D. It's definitely not a straightforward bug. Keep up the good work, I'm sure you'll find the fix :) !

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 23, 2015

@UKDeveloper99 have you tried with "extrude + 2 pixels of padding/border"? did it work?

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 23, 2015

@ricardoquesada I believe I tried it before and it didn't make a difference, but I'll try it again now and see if it makes a difference, so for clarity I will use. Extrude: 1, Padding: 2, Border: 2 and Projection::_2d

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 23, 2015

yes, please. thanks.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 23, 2015

@ricardoquesada Yes I can confirm this appears to look correct to me. It's a little difficult to tell with the extrude option as obviously the outer edge of pixels looks identical so without a pink or yellow line like you have used you it's a little difficult to see. But it definitely doesn't look anywhere near as bad as the CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL fix, with the visual stretching and shrinking. I don't think the top line of extruded pixels is flashing in and that's the most important thing.

I still think the underlying cause needs to be resolved and I hope you can get it in to v3.8 as planned (e.g. other developers may run in to this problem and not be able to find this workaround). However I can work with this solution for now. Thanks.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 23, 2015

@ricardoquesada @fusijie out of interest is there any performance implications or features that may stop working with 2D projection?

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 23, 2015

2d projection is not really needed. But if you are not going to use 3d features, I suggest using it. No performance implications in using one or the other.

Creating spritesheets with extrude and 2 pixels of padding/border is pretty much what I have been recommending from day one in cocos2d-iphone and cocos2d-x. All spritesheets must be created like that.

You are not triggering the bug you mentioned before... that one could be fixed by using highp.
You are triggering another one, which could be fixed by using extrude + border, or by changing some shaders to round up/down the floats...
I think this bug is low priority right now since the workaround is trivial to implement... and perhaps the "real fix" will have performance implications.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 24, 2015

@ricardoquesada I know they are recommended, when you select the cocos2d preset in TexturePacker in turns them on for you. I was experimenting with them turned off because when I was trying to fix the original bug they weren't making a difference.
Of course they help with the various OpenGL artifacts/issues that can crop up, as can pre multiplied alpha.

I don't think using highp is an option, I tested that last week and it really makes a difference to the fps. And obviously the more stuff you have in the scene the more noticeable that difference is.

I did experiment with rounding, initially I thought it might help if all the positions were on rounded coordinates. Something like.... floor(position.x + 0.5f) as an example. That didn't help. I wouldn't know which parts to round in the shader.

Hmm I agree the workaround is trivial, but the fact is unless it is put in to the documentation/ programmers guide. The average user isn't gona know what they need to do to fix it. It's trivial for you and me but it's not something that's enabled by default.

I highly agree that if the "real fix" has performance implications then it can't be considered at all, it would be interesting to know if you had some idea of what the "real fix" might be, just out of curiosity.

@ricardoquesada

This comment has been minimized.

Copy link
Contributor

ricardoquesada commented Jul 24, 2015

@UKDeveloper99 good point. We should put it in the Programmers Guide!

The "real fix" has to do with subpixeling... at least that is my understanding of this problem. And the fix is to prevent subpixeling.

So, rouding the pixels, as you said before, should fix this. But I wouldn't know right now what is the best way to do it.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 24, 2015

@slackmoehrle Programmers Guide^

@slackmoehrle

This comment has been minimized.

Copy link
Contributor

slackmoehrle commented Jul 24, 2015

Yes, we should definitely add. If you want to take a pass at the content to
add I can then put it in the correct format, make sure it makes sense, etc,
etc.

On Fri, Jul 24, 2015 at 11:49 AM, Mark notifications@github.com wrote:

@slackmoehrle https://github.com/slackmoehrle Programmers Guide^


Reply to this email directly or view it on GitHub
#12847 (comment)
.

@UKDeveloper99

This comment has been minimized.

Copy link
Author

UKDeveloper99 commented Jul 24, 2015

@slackmoehrle sure, if I get a spare moment. This project is really intense at the moment.

@pandamicro pandamicro modified the milestones: next, v3.8 Aug 19, 2015

@minggo minggo removed the module:renderer label Nov 3, 2017

@drelaptop drelaptop modified the milestones: v3.10, 3.18 May 23, 2018

@drelaptop drelaptop removed this from the 3.17.1 milestone Nov 12, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.