SFML community forums

Help => Graphics => Topic started by: _Fiction_ on June 22, 2013, 07:36:19 am

Title: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 07:36:19 am
EDIT: My initial problem was solved but I'm having a related issue which I detail on the next page. Thanks :)

I am having a problem with tearing/artifacts when rendering tiles. When rendering normally, I get the lines in the first image, which appear only horizontally. I have tried several approaches, and the only option that has successfully removed them is to use Texture::setSmooth(false) on my map textures. However, this creates a second (although less obtrusive) issue (second image) where I get some pixel choppiness on my slopes. I would like to remove both of these issues, as opposed to simply having to choose between the lesser of two evils. Any suggestions?

(http://i.imgur.com/SLxOrzh.png)
Title: Re: Tile tearing vs texture smoothing
Post by: FRex on June 22, 2013, 07:39:30 am
Smooth is off by default.
Are these actual tiles or are they rotated sprites/whatever?
Maybe show some code. ;D
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 07:45:38 am
I think at some point in my code I turn smoothing on for all textures (so that the player and enemies rotate smoothly), which is why I have to unsmooth the map textures. Either way, its just a boolean value.

I'm not sure what you mean by "actual tiles." They are not rotated in any way, and are part of a larger texture. What part of the code are you interested in? I 've implemented it several different ways (render texture, drawing each as a sprite, vertexarray) and all have the same results.
Title: Re: Tile tearing vs texture smoothing
Post by: FRex on June 22, 2013, 07:48:11 am
Have you tried messing with texture coords and/or position coords of vertices in quads and seeing if it helps(setting them to full integers or floats ending in .5)?
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 07:55:18 am
Yes. Although there is a slight change visually, its the same change as simply moving the camera/character on y-axis, meaning some lines get thinner, some lines disappear, and other lines appear (they flicker if you move through the y-axis quickly). As a note, I DO have rounding on the position of my camera/view, as I recall that the lack of rounding on view position was the cause of a similar line issue for another user on the forum.
Title: Re: Tile tearing vs texture smoothing
Post by: FRex on June 22, 2013, 08:27:53 am
I'm trying to reproduce it myself, simple, self contained int main and texture image that contains the problem would be helpful to experiment with.
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 09:19:16 am
I will try to make the smallest version possible, although I am not as experienced as you with SFML (going off of post count) so it might take me a while longer to create a test case.
Title: Re: Tile tearing vs texture smoothing
Post by: FRex on June 22, 2013, 09:24:30 am
This is very infamous bug/artifact, I kind of ran into it once, not sure if I fixed it or not or if it was appearing on certain machines only.
I tried that, and it works ok with a 2x2 tilesheet with 32x32 tiles(attached).
Changing bump in vert made line artifacts, but other two don't change a thing.

#include <SFML/Graphics.hpp>


sf::Vector2f vert(int x)
{
        const sf::Vector2f bump(0.f,0.f);
        switch(x)
        {
        case 1:return bump+sf::Vector2f();
        case 2:return bump+sf::Vector2f(0.f,32.f);
        case 3:return bump+sf::Vector2f(32.f,32.f);
        case 4:return bump+sf::Vector2f(32.f,0.f);
        }
}
sf::Vector2f texc(int x)
{
        switch(x)
        {
        case 0:return sf::Vector2f();
        case 1:return sf::Vector2f(32.f,0.f);
        case 2:return sf::Vector2f(0.f,32.f);
        case 3:return sf::Vector2f(32.f,32.f);
        }
}
int main(int argc,char * argv[])
{
        const sf::Vector2f bump(0.8f,0.3f);
        const int mapx=5;
        const int mapy=5;
        const int map[mapx][mapy]=
        {
                {3,3,3,3,3},
                {0,3,3,3,3},
                {3,0,3,3,3},
                {3,3,1,1,1},
                {3,3,3,3,3},
        };

        sf::RenderWindow app(sf::VideoMode(640,480),"s");
        app.setFramerateLimit(60);
        sf::Texture tex;
        tex.loadFromFile("img.png");
        sf::VertexArray array;
        array.setPrimitiveType(sf::Quads);

        const float pos=64.f;

        for(int x=0;x<mapx;++x) for(int y=0;y<mapy;++y)
        {
                const sf::Vector2f vec=texc(map[x][y]);

                array.append(sf::Vertex(bump+sf::Vector2f(pos*x,pos*y),vert(1)+vec));

                array.append(sf::Vertex(bump+sf::Vector2f(pos*x,pos*(y+1)),vert(2)+vec));

                array.append(sf::Vertex(bump+sf::Vector2f(pos*(x+1),pos*(y+1)),vert(3)+vec));

                array.append(sf::Vertex(bump+sf::Vector2f(pos*(x+1),pos*y),vert(4)+vec));
        }
//      tex.setSmooth(true);
        while(true)
        {
                sf::Event eve;
                while(app.pollEvent(eve));

                const sf::Vector2f add(0.67325f,0.12354f);
                sf::View v=app.getDefaultView();
                v.setCenter(add+sf::Vector2f(sf::Mouse::getPosition(app)));
                std::printf("%3.2f %3.2f\n",v.getCenter().x,v.getCenter().y);
                app.setView(v);

                app.clear();
                app.draw(array,&tex);
                app.display();
        }
        return 0;
}
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 09:38:18 am
"Changing bump in vert made line artifacts, but other two don't change a thing." Can you rephrase this line? I'm not sure I understand.

(Also, excellent job on the test case. Much better than mine would have been.)
Title: Re: Tile tearing vs texture smoothing
Post by: FRex on June 22, 2013, 09:50:40 am
sf::Vector2f vert(int x)
{
    const sf::Vector2f bump(0.f,0.f);
this bump value must be 0 0 or line artifacts happen, the one that gets added to position:
 const sf::Vector2f bump(0.8f,0.3f);
and view center:
 const sf::Vector2f add(0.67325f,0.12354f);
can be set to weird values(as shown) and everything looks ok.

Quote
(Also, excellent job on the test case. Much better than mine would have been.)
Ok, but if that renders without any artifacts on your card then you must have done something wrong in your code or texture.
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 11:11:32 am
Okay, I got a chance to actually test your code. I see you commented out setSmooth( true ). When I uncomment that line (makes the diagonals noticeably smoother) there are small lines between every tile. I'm trying to avoid the jagged pixel edges and the artifact lines simultaneously.
Title: Re: Tile tearing vs texture smoothing
Post by: FRex on June 22, 2013, 11:26:23 am
There are no jagged pixels appearing for me, everything is rendered 1:1 , unless by that you mean the pixels are not smoothed out and you want to use set smooth while having no artifacts.

Use this vert function and uncomment setSmooth true and see if these are the results you seek.
sf::Vector2f vert(int x)
{
        const sf::Vector2f bump(0.f,0.f);
        switch(x)
        {
        case 1:return bump+sf::Vector2f(0.5f,0.5f);
        case 2:return bump+sf::Vector2f(0.5f,31.5f);
        case 3:return bump+sf::Vector2f(31.5f,31.5f);
        case 4:return bump+sf::Vector2f(31.5f,0.5f);
        }
}
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 12:22:42 pm
Thank you for your help  ;D! That seems to be the behavior I'm looking for. I'm going to attempt to apply this solution to my code, and I will post any problems/results in the morning.
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 07:32:06 pm
Is it more efficient to create a VertexArray of a large map a single time, and then draw the entire map each frame, or to create a new vertex array of a clipped section of the map each frame based on the view?
Title: Re: Tile tearing vs texture smoothing
Post by: Nexus on June 22, 2013, 07:34:16 pm
I would guess creating (or actually filling) the vertex array again is faster, but you have to measure. Of course it depends on the map size.

Filling happens on the CPU. In the average case, there is not even a dynamic allocation, since you can reuse the container. So the operation involves only copying some objects.
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on June 22, 2013, 07:41:39 pm
What about if I have multiple tilesets making up the map? From what it looks like, a VertexArray only lets you draw from a single texture, so I think I would have to make a VertexArray for each texture in the scene. This would force me to do dynamic allocation each frame as the number of tiles from each tileset would change each frame. Is there a way to get around this?

EDIT: Actually, I'm pretty sure that I can find the answer to something like that somewhere on the forum. Don't want to waste anyones time with something off-topic. Thank you for your help :D

EDIT2: Here's the working version :)
(http://i.imgur.com/nN2Ohfr.png)
Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on August 10, 2013, 04:47:32 am
Since this is related to the same issue I thought I would post it here. I originally thought I had solved my problem because the diagonals were smoothed just fine. However, we recently added in a grass texture, and with smoothing on, I get a white border on the outside of the grass, as well as an obvious line between the tiles, which should fit perfectly.
(http://i.imgur.com/1NRx0w9.png)

If I remove the half-pixel addition to each size of a tile that was recommended earlier in this thread, the line between the tiles is now gone, but all of the grass now has a white border (and the tiny lines of pixels that jut out from the OP return).
(http://i.imgur.com/BH9rgJf.png)

To avoid the jutting pixels and the white grass tips, I turn smoothing off. Both of these issues are gone, but my original problem now remains. The diagonals are once again adding extra pixels, creating a jagged look. Another but also came up, which adds/removes single lines of pixels when i move around. I have highlighted both issues in the image. The vertical line of pixels is tough to see, but its a brown line that has been added to the bottom image. This can be avoided if I implement the solution from earlier, except instead of .5 extra pixels around each tile, I add an entire pixel. This of course adds the line between the grass and the floor again, and causes a bunch of other issues.

(http://i.imgur.com/un7F0O1.png)


In case it comes up, I am rounding my view coordinates to an integer, so that is not the issue. The resolution I am using on my view is 1920, 1080. When I zoom in far enough on the issues in the last image, they both go away. Note sure if that helps. My current code for drawing my tiles is:

for( int tx = leftTile; tx < rightTile; ++tx )
                {
                        for( int ty = topTile; ty < bottomTile; ++ty )
                        {
                                if( staticTileSets[tx][ty] != NULL )
                                {
                                        int tc = ((tx - leftTile) + (ty - topTile) * viewHalfWidthTiles * 2) * 4;

                                        VertexArray &map = *(texVertexMap[staticTileSets[tx][ty]->texture]);
                                        // define the position of the 4 points of the current tile
                                        map[tc + 0].position = sf::Vector2f((tx + 0) * tileSize, (ty + 0) * tileSize);
                                        map[tc + 1].position = sf::Vector2f((tx + 0) * tileSize, (ty + 1) * tileSize);
                                        map[tc + 2].position = sf::Vector2f((tx + 1) * tileSize, (ty + 1) * tileSize);
                                        map[tc + 3].position = sf::Vector2f((tx + 1) * tileSize, (ty + 0) * tileSize);

                                        // define the texture coordinates of the 4 points of the current tile
                                        float blend = .5f;
                                        int ix = staticTileSets[tx][ty]->GetSubRect( staticLocalID[tx][ty] ).left / tileSize; // X index of the tile in the tileset
                                        int iy = staticTileSets[tx][ty]->GetSubRect( staticLocalID[tx][ty] ).top / tileSize; // Y index of the tile in the tileset ;
                                        map[tc+ 0].texCoords = sf::Vector2f((ix + 0) * tileSize + blend, (iy + 0) * tileSize + blend);
                                        map[tc+ 1].texCoords = sf::Vector2f((ix + 0) * tileSize + blend, (iy + 1) * tileSize - blend);
                                        map[tc+ 2].texCoords = sf::Vector2f((ix + 1) * tileSize - blend, (iy + 1) * tileSize - blend);
                                        map[tc+ 3].texCoords = sf::Vector2f((ix + 1) * tileSize - blend, (iy + 0) * tileSize + blend);
                                }
                                else
                                {
                                }
                        }
                }
               
                for( std::map<sf::Texture*, sf::VertexArray*>::iterator mapIt = texVertexMap.begin();
                        mapIt != texVertexMap.end(); ++mapIt )
                {
                        window->draw( *(*mapIt).second, (*mapIt).first );
                }
 

Title: Re: Tile tearing vs texture smoothing
Post by: _Fiction_ on August 17, 2013, 06:37:43 am
Is bumping allowed here? Doesn't seem like I'm getting any responses :(