I have an issue with a tiled map I'm displaying. The map consists of 18x9 tiles, each 256x256 pixels in size. There's one unique PVRTC-compressed texture for each tile (no atlases or shared textures among tiles). The textures contain mipmap levels and were created using Apple's texturetool. Everying looks smooth until I start pinch zooming into my opengl view (pinch has been implemented manually using the touchesMoved method). Suddenly there's a distortion at nearly each tile's edge. It looks as though the texture sort of loops (i.e.: the right most texel is assigned to the left most pixel of the polygon). I use these obvious texture cords:
Edit... sorry, didn't look closely enough at your code.
It looks like your texture clamping isn't working. All I can think of is that you didn't have your texture "bound" when you specified your clamping. (You need to specify the clamping parameter for every texture you create.)
Edit... sorry, didn't look closely enough at your code.
It looks like your texture clamping isn't working. All I can think of is that you didn't have your texture "bound" when you specified your clamping. (You need to specify the clamping parameter for every texture you create.)
I'm using the code from the PVRTexture example to create the textures. I've also added these calls prior to glGenTexture and glBindTexture:
All tiles are separate triangle strips (i.e. two triangles per tile). Reducing the tiles to one still shows the distortions but less noticable.
If I change the texture filtering to GL_NEAREST the effect is still there but also less noticable.
Mipmapping isn't the problem. But, if you want any glTexParameter call to work, it has to come AFTER the bind for that particular texture. Doing things before the bind will, in effect, change the corresponding parameter on the previously bound texture (if there was one.)
Mipmapping isn't the problem. But, if you want any glTexParameter call to work, it has to come AFTER the bind for that particular texture. Doing things before the bind will, in effect, change the corresponding parameter on the previously bound texture (if there was one.)
Do I only need to set these params in the process of texture creation or also when I'm rendering?
Here's the code I'm using to load the textures:
initWithContentsOfFile: is passed a string containing the texture's file path
- (id)initWithIndex:(NSInteger)index forMapSize:(CGSize)size {
// find the row and column
GLshort row = (NSInteger)(index / size.width);
GLshort col = (NSInteger)(index % (NSInteger)size.width);
GLshort x = col << 8;
GLshort y = row << 8;
coords[0] = x;
coords[1] = y + 256;
coords[2] = x + 256;
coords[3] = y + 256;
coords[4] = x;
coords[5] = y;
coords[6] = x + 256;
coords[7] = y;
NSString *txName = [NSString stringWithFormat:@"tile%d", index];
texture = [[PVRTexture alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:txName ofType:@"pvr"]];
return self;
}
coords is a Glshort-array. Each tile consists of two triangles. Row- and column indexes are multiplied by 256 as this corresponds to the size of the tiles.
If I set the filtering within drawTile the application slows down dramatically. Also not that I'm not doing any optimization yet. My first priority is getting this thing to work without 'em texture distortions.
should be moved to within the createGLTexture, right AFTER the bind command. You only need to specify if when you create the texture, but you need to do it for every texture you create, right after you "bind" it.
should be moved to within the createGLTexture, right AFTER the bind command. You only need to specify if when you create the texture, but you need to do it for every texture you create, right after you "bind" it.
Did that. Now the distortions are almost gone. Still they're quite noticable:
Yeah... I seem to remember running in to this as well at one point... the problem is that you need to specify border texels, but opengles doesn't allow that (at least, not version 1.1.) I think what's going on is that you are not getting the clamping you want in the mipmaps. Are you generating the mipmaps yourself? If so, make sure you have the clamping for each texture turned on before you generate the mipmaps.
My solution to this problem (which is probably not the best one) is just to make sure that none of my textures run up flush with the edge of the texture. In the one case where I can't avoid that, I use texels within the texture (6 rows, I think) as my border texels. But in your case that will mean resampling all of your textures to use some of the textures texels as border texels. It will also mean that you're texture coordinates will have to be updated so that they map to the "real" corner of the texture which will now be interior to your texture. That probably isn't the right solution, but it was the one I went with. It was a long time ago that I ran across this problem so my memory is a bit hazy.
Anyone else run in to this problem? I *think* (but I don't know) the problem is that mipmap levels other than level 0 ALWAYS have clamping turned off (that is, they always wrap instead of clamp.) I don't think that is what opengles is supposed to do, but I think that's what's going on. This may only be a problem with pvr textures.
Yeah... I seem to remember running in to this as well at one point... the problem is that you need to specify border texels, but opengles doesn't allow that (at least, not version 1.1.) I think what's going on is that you are not getting the clamping you want in the mipmaps. Are you generating the mipmaps yourself? If so, make sure you have the clamping for each texture turned on before you generate the mipmaps.
My solution to this problem (which is probably not the best one) is just to make sure that none of my textures run up flush with the edge of the texture. In the one case where I can't avoid that, I use texels within the texture (6 rows, I think) as my border texels. But in your case that will mean resampling all of your textures to use some of the textures texels as border texels. It will also mean that you're texture coordinates will have to be updated so that they map to the "real" corner of the texture which will now be interior to your texture. That probably isn't the right solution, but it was the one I went with. It was a long time ago that I ran across this problem so my memory is a bit hazy.
Anyone else run in to this problem? I *think* (but I don't know) the problem is that mipmap levels other than level 0 ALWAYS have clamping turned off (that is, they always wrap instead of clamp.) I don't think that is what opengles is supposed to do, but I think that's what's going on. This may only be a problem with pvr textures.
Thanks! I use texturetool to generate the mipmap levels, so I have no influence on the clamping. So you mean if I sort of inset my map tile by adding 6 pixels to each of the edges if would work? Gonna try that... only I don't know how to teach ImageMagick to do this yet :-)
BTW: just tried to emulate what you've suggested by setting the texture coords to 0.1..0.9 and it did work. No distortions anymore. Now I know what to do.
Thanks! I use texturetool to generate the mipmap levels, so I have no influence on the clamping. So you mean if I sort of inset my map tile by adding 6 pixels to each of the edges if would work? Gonna try that... only I don't know how to teach ImageMagick to do this yet :-)
BTW: just tried to emulate what you've suggested by setting the texture coords to 0.1..0.9 and it did work. No distortions anymore. Now I know what to do.
Thanks again! I really appreciate it!
Steff
Actually, you can try just insetting your texture coordinates without resampling your texures first. E.g., if your textures are 256x256, try setting your texcoords to vary from [0.5/255.0 .. 254.5/255.0] or [1.0/255.0 .. 254.0/255.0]. That might be enough for your purposes.
Actually, you can try just insetting your texture coordinates without resampling your texures first. E.g., if your textures are 256x256, try setting your texcoords to vary from [0.5/255.0 .. 254.5/255.0] or [1.0/255.0 .. 254.0/255.0]. That might be enough for your purposes.
Whoops, I already resampled my textures - would have had to do that anyway as I wanted to switch to 512x512 textures. Works fine now except one thing: I can't seem to get the tex coords right. My inset is 6px so the coords should be [6.0/512 ... 506/512] right? Still I see black border texels, especially when zooming out.
Whoops, I already resampled my textures - would have had to do that anyway as I wanted to switch to 512x512 textures. Works fine now except one thing: I can't seem to get the tex coords right. My inset is 6px so the coords should be [6.0/512 ... 506/512] right? Still I see black border texels, especially when zooming out.
Best regards,
Steff
Don't fill your border texels with black. They need to be the same color as their corresponding interior texel. So, your texture should like like you drew it in a quad that was slightly too big, and you drew it with clamping turned on. You are trying to simulate the effect of clamping yourself since the iphone isn't doing it right.
And you probably don't need to use 6, I'm just saying that I think that's what I'm using.
As for whether the range should be [6.0/512.0 ... 506.0/512.0] or
[6.5/512.0...] or [5.5/512.0...] I don't know... you'll just have to experiment until it looks seamless.
Again, I have no idea if this is the right way or the best way to do this, I'm just saying it works for me.