Well a reduction from 4 to 1 pixel padding is still great! thanks cj for finding this holy Grail! Maybe @cj could have a look at issue 737, I wouldn't be surprised if they are linked...
Anyway, well done!
A fast, easy to use, free, and community supported 2D game engine
Well a reduction from 4 to 1 pixel padding is still great! thanks cj for finding this holy Grail! Maybe @cj could have a look at issue 737, I wouldn't be surprised if they are linked...
Anyway, well done!
Actually, in theory those formulas should not work at all that you presented.
Texture mapping is essentially the image size ranging from 0,0 to 1,1 in 3D. You shouldn't have to times by 2 the rect position or size, or the atlas image size either.
If you keep them all pixel based to begin with then there only needs to be one conversion to the range of 0 to 1.
the rect x,y,width,height are all in pixels, and the atlasWidth and height are also in pixels
If they are all pixel based and the maximum size is atlasWidth and atlasHeight then technically just dividing by atlasWidth and atlasHeight will results in a value of 0 to 1. However, it will only be 0 to 1 if the left side of the equation is <= atlasWidth or atlasHeight and >= 0.
If we have an atlas of 512x512 and a rect of x=20,y=20,width=512,height=512. Then we have a problem, because the rect + either the x / y will cause the amount to be greater than atlasWidth or atlasHeight. Thus, you will get a value larger than 1. However if we have rect of x=0,y=0,width=512,height=512 then everything is fine a dandy because everything will stay within the range of the maximum atlasHeight and atlasWidth. Therefore everything will be 0 to 1.
float right = (rect.x + rect.width) / atlasWidth; // problem: if rect.x+rect.width > atlasWidth then the result will be a value larger than 1 which is no go! The value for texels must be between 0 and 1!
float left = rect.x / atlasWidth; //problem: if rect.x > atlasWidth then the result will be a value larger than 1 which is a no go! The value for texels must be between 0 and 1!
float top = rect.y / atlasHeight; // same problem as above
float bottom = (rect.y + rect.height) / atlasHeight; // same problem as above
//Another problem is the fact if someone gives a negative value for rect.x, rect.y or rect.width, rect.height. This is a no go either because it is less than 0!
//Solution clamp the values to range from 0 to 1
top = clamp(top);
left = clamp(left);
right = clamp(right);
bottom = clamp(bottom);
/**
* Simple Clamp function for 0 to 1
* @return float
*/
float clamp(float value)
{
if(value > 1)
{
return 1.0f;
}
else if(value < 0)
{
return 0.0f;
}
else
{
return value;
}
}@Metric
What you describe for mapping a rect of pixels texture coordinates in the range [0,1] is what we all assumed before. It does make logical sense that a rect of pixels (0,0,512,512) maps with tex coords (0,0),(1,1).
But, in practice, that naive implementation doesn't work so well. The formulas I provided above simply change the sample point from the corner of a pixel (at the intersection of 4 pixels) to the center (where there is only one color available).
Regarding your understanding of valid values for the u,v range... You are not required to keep them in the range [0,1]. Depending on the texture wrap setting, the texture may clamp or repeat. There is no need to manually clamp the values in your program code.
Read: http://www.opengl.org/wiki/Texture#Edge_value_sampling
Using the patch provided by @CJ I get the following build error: 'rectRotated_' undeclared (in CCSprite.m).
What other update would I be missing?
Thanks! I can't wait to try this on my 'black line' issue!!
Harv
Thank you both! I will do!
Hi,
I don´t know if my problem is the same issue but even after updating to the latest development branch from git I´m still getting strange artifacts when using sprites. I want to display them crisp and clean, so I set the AliasTexture param for them:
[sprite.texture setAliasTexParameters];
I also changed that subpixel stuff (set it to 0) in ccConfig.h (for node and spritebatchnode). I tried
[CCDirector setDirectorType:CCDirectorProjection2D]
It all didn´t help. This is how my sprites look (normal and with artifacts, 2 x magnified to see the issue better)

I also tried different positions on screen, different sizes. No matter what I do - nothing helps... I´m getting nuts...
Thanks for any help!
Marco
PS: EDIT: Same issue with 0.99.5 beta - just tested some seconds ago... It really looks as if the sprites are resized a bit or something like that...
PPS: Don´t know if it matters - it´s an iPad only project. So the issue displays on an iPad.
@marcotronic The issue you describe sounds similar to this post:
http://www.cocos2d-iphone.org/forum/topic/5760
But he said that setting a 2D projection fixed the issue. Can you upload a simple project that just replicates the issue? I'll take a look at it to try to fix it.
Hi,
I´ve isolated the issue in a small project:
The artifacts show like in my examples above:
http://www.marcotronic.com/forums/ArtifactTest.zip
Any ideas?
Thanks a lot...
Marco
PS: I know the framerate is very low (due to the sprite as background image) but in my "real" project I use that trick with placing an empty sprite first and adding a child with the actual backgorund image with speeds up the FPS again... But the issue shows either way...
@CJ: I´ve seen your posting after posting my example... Thanks a ton in advance for looking at it! That 2DProjector stuff didn´t help... In my little test project posted above I don´t use it.
Marco
@marcotronic I tested your project and it does show the artifact you describe. But upon setting the projection matrix to 2D (as Steve Oldmeadow pointed out in that other post) it solves the issue.
So, just add this after you get a reference to the shared director in your app delegate:
[director setProjection:CCDirectorProjection2D];Thanks a lot, CJ. You are right. In my test project it actually works but in my "real" project this has no effect... I have to check the differences... (As it didn´t work in my real project I didn´t set it in my test project because I thought it just wouldn´t work...)
Marco
@CJ: Yes, the texture can wrap, but it still doesn't make sense to put it at the center of a pixel. It shouldn't have artifacts when mapping from 0 to 1 in direct relation to the pixels.
Basically, there is something else going on in the cocos2d engine dealing with creating the textures for the sprites / compressing / uncompressing. It could even be the hardware of the iphone interfering with compression / uncompression. However, I have a feeling it is more to do with the actual compression / uncompression / converting algorithms in cocos2D.
What I am saying is, you are applying a fix, but not to the real issue behind the problem. Your fix is more of a bandage then a direct stitching of the real problem.
You also should not have artifacts in the textures in the 3D Projection if the texture is being created properly / uncompressed.
I have yet to experience this artifact issue / flickering in the Java version I am working on, on my desktop or laptop. It is still using the direct 0,0 to 1,1 mapping. Of course, I am using the built in bufferedImage object in Java when converting to ARGB, RGB, RGBA, RBG, etc. Also, I am using pngs to test with.
@Metric I see your point. I started doing some testing based on Apple's GLSprite example here
https://developer.apple.com/iphone/library/samplecode/GLSprite/Introduction/Intro.html
I'm building up from that using the same texture and projection settings that cocos2d uses and manually adding support for texture atlas one step at a time until I can reproduce the issue. If I cannot reproduce the issue then it must be something else in cocos2d that is introducing the problem.
Stay tuned...
@CJ, thanks again. Now my "real" poject is working, too. Don´t ask me what exactly the problem was, but now it´s working :o) But now I have another problem:
When I use the 2DProjection type my scene replacements with CCPageTurnTransition look awful now. When I comment out the 2DProjection stuff it´s okay - the page transitions look beautiful but whith 2Dproj. turned on they aren´t rendered correctly any more - the background of the scenes, when the scenes/pages turn, is black.
Is there any way to have 2Dprojection and still use those PageTurnTransitions correctly?
Thanks,
Marco
@marcotronic You may be able to switch to a 3D projection just before your transition, and then put it back to a 2D projection after the transition ends. (You may want to just subclass the transition you want and put your code in your new class).
@CJ: Cool idea with the subclass! Thanks a lot for the quick response! :o)
Marco
Hi guys,
You might want to check pages 320 and following of the openGL superbible.
http://amzn.to/aRoMwF (well 5th edition is just out but I don't have it).
I remember also finding a website that explained the problem and the solutions very well when I was writing my game, but I can't find it anymore in my bookmarks, I will look again.
Can't find the page with a nice discussion of the problem and the various solutions (clamping, border duplication, texel middle coordinate, border pixel), but I think that discussion is not bad:
http://www.gamedev.net/community/forums/topic.asp?topic_id=543816
@everyone
Metric and obj1 have provided good information, and I would like to update you all on the results of my testing (I did my tests using Apple's GLSprite example built up to a working test suite and so I did not use cocos2d in order to isolate the rendering from other issues that cocos2d may be introducing.)
The "fix" I provided at the start of this thread is actually doing the following:
1. Stretching the texture over your sprite by 0.5 pixels in 4 directions.
2. This resolves the edge to edge issues between tiles but at the cost of scaling up your texture slightly. (the cost is visual, not cpu/gpu cost)
Verdict:
Stretching your images or padding your image with transparent pixels are not the solution to the real issue.
Solution:
The correct way to fix the issue is to pad a border that copies the pixels already on the edge. In some cases this is transparent or semi-transparent, in others it is solid color, it all depends on your images. Since this puts the issue back in the realm of image preparation, I think the zwoptex tool could add a feature to automatically pad the image out by n pixels w/o changing the desired rect coordinates. In the case of using mip-maps you may need to pad more than 1 pixel.
For example if you have an image that is 7x7 with a sprite defined as the rect (2,2,3,3)
XXXXXXX
XXXXXXX
XXRGBXX
XXRGBXX
XXRGBXX
XXXXXXX
XXXXXXX
Then after padding the image would be:
XXXXXXX
XRRGBBX
XRRGBBX
XRRGBBX
XRRGBBX
XRRGBBX
XXXXXXX
Notes:
@riq you should probably revert the texture coord stuff back to using the 0,1 range unaltered. Sorry for the work you've put in over the last few days on putting in the code I supplied.
@zwopple let me know if you want assistance in writing code to auto pad the images. I have a project that does something similar on github here:
http://github.com/wiseganesha/PNGPOTimizer
Ok got this all, but I really didn't notice any visual problems applying CJ's patch. And I hate using "artifact-fixer" or thinking about borders for images. So can anybody show me how that little stretching affects image quality in "real life"? If it's not that significant I suggest making
#define CC_PREVENT_ARTIFACTS_BY_STRECHING_TEXEL 1
as default...
@riq cool :)
For the less technically inclined it would be a great addition to zwoptex's export options :)
One other thing to note about the "correct" fix is that it will resolve the tiling issue nicely, but it will not look nice for floating sprites that are rotated because there is no edge anti-aliasing done by the iPhone so you will get jaggies around the sides if your texture goes right up to the edge of your polygon. The solution to that is to add a transparent border inside the sprite rect AND pad that transparent border out beyond the rect as well :)
Here is a visualization of my tests:

@crmagicxxx
The "real life" effects are two-fold:
1. Your sprites will be a little less sharp as they appear scaled up a bit.
2. If you do use floating sprites (as in not in a tilemap) and do not pad a transparent border then rotating your sprite will show off [sarcasm]the amazing aliasing capabilities of the iPhone's renderer[/sarcasm]
@crmagicxxx +1
I tried using numerous patches and fixes including artifact fixer and I was not able to resolve my artifacts on my TMX tilemap - CJ's code did!
I'm pretty sure I'll be sticking with this and it will be a pain if I have to remember to toggle the CC_PREVENT_ARTIFACTS_BY_STRECHING_TEXEL setting. <- my $0.02 that's all :-)
Copying the edge color into the border is the solution i've used so far, and I'd like to point out that there is a script out there that does it for you when creating your sprite sheet:
http://code.google.com/p/cocos2d-iphone/issues/detail?id=549
Unfortunately this updated version of zombie's mkatlas.pl script has still (10 months ;)) not made it into the tree, but you can download it and use it from the link above.
@hactar thanks for the link :)
One thing I was just thinking is that you can make the case to always copy the edge color out into the border because if you want your floating sprites to look anti-aliased they should actually contain a transparent border INSIDE their texture rect.
@riq: I did actually send you a simple test file a while ago via email, but I'll attach it to the issue.
Or I wont, google-code says: Issue attachment storage quota exceeded. :/
I forgot to also mention that applying sub pixel stretches will blur peoples pixel artwork. I've had requests asking that offsets are never half pixel values to avoid blurring. This is more of a subpixel rendering issue but some people do prefer that their sprites are pixel sharp because of their artwork style.
@CJ
I wont need help applying this to Zwoptex per say.. the concept is easy to just stretch the borders 1px but leave the coordinates the same. The problem is I'm not to keen on implementing it until it has proper UI supporting it.
I'm not necessarily turned away by the idea of some help but since it's a commercial product I obviously want to make sure that the circumstances are right for others to come on board and patch features in.
I probably wont have time for this until the new sprite inspector is in with aliasing which is about 2-4 weeks out.
-Robert
You must log in to post.