Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Problem rendering tiles (tearing?)  (Read 12182 times)

0 Members and 1 Guest are viewing this topic.

jmcmorris

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Problem rendering tiles (tearing?)
« on: January 03, 2012, 01:20:54 am »
Hello, I was hoping someone could help me out with a problem.

I have a map made up of a tile grid. Rendering consists of using a single sprite and drawing it once for each tile. The sprite's position is changed for every tile and its subrect is adjusted according to the tile. Here is a code snippet of it.

Code: [Select]
for (Int16 y = startY; y < startY + height; ++y) {
    for (Int16 x = startX; x < startX + width; ++x) {
        Int16 tileId = tiles[y][x];

        //Continue to the next tile since this one is empty
        if (tileId == 0) {
            continue;
        }
        m_sprite->SetPosition(x * m_tilemapData->tileWidth + m_offset.x, y * m_tilemapData->tileHeight + m_offset.y);

        //Update the sub-rectangle of the sprite if this is a different tile from the previous one
        if (tileId != previousTileId) {
            Vector2i position = m_tilemapData->getTilePosition(tileId);
            tileRect.Left = position.x;
            tileRect.Top = position.y;
            m_sprite->SetSubRect(tileRect);
            previousTileId = tileId;
        }

        //Draw the tile!
        renderTarget->Draw(*m_sprite.get());
    }
}


The problem is that occasionally all of the tiles will tear? at the bottom or right side (never both). This only happens when I'm moving the views around.

I have SetFramerate to 60 and have texture::SetSmooth(false) for the tilemap texture. I tried using vsync instead of SetFramerate but the problem persisted. I managed to get a screenshot of the problem and along with it is how the tiles are suppose to look.


Good Tiles


Bad Tiles


I'm going to start working on a small code sample that can reproduce the problem. In the meantime, let me know if you have any ideas and thanks in advance!

omnomasaur

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • http://www.omnomasaur.com
Problem rendering tiles (tearing?)
« Reply #1 on: January 03, 2012, 01:38:28 pm »
This sounds to me like an error with sprite position being floating point values.  

Since the position of the sprite drawn on the screen has to match up with pixels on the screen the floats have to be converted to integers.  

The problem arises when you have a position float that rounds to an integer in the direction opposite that the previous position did, causing tiles to either overlap by 1 pixel or be 1 pixel apart.  

The fix for this would be to ensure that all your position floats round off in the same direction using a floor() or ceil() to ensure that the sprite's position is exactly that of the pixels it is drawing to.

In your code I believe it would look like this.  
Code: [Select]

for (Int16 y = startY; y < startY + height; ++y) {
    for (Int16 x = startX; x < startX + width; ++x) {
        Int16 tileId = tiles[y][x];

        //Continue to the next tile since this one is empty
        if (tileId == 0) {
            continue;
        }
        m_sprite->SetPosition(floor(x * m_tilemapData->tileWidth + m_offset.x), floor(y * m_tilemapData->tileHeight + m_offset.y));

        //Update the sub-rectangle of the sprite if this is a different tile from the previous one
        if (tileId != previousTileId) {
            Vector2i position = m_tilemapData->getTilePosition(tileId);
            tileRect.Left = position.x;
            tileRect.Top = position.y;
            m_sprite->SetSubRect(tileRect);
            previousTileId = tileId;
        }

        //Draw the tile!
        renderTarget->Draw(*m_sprite.get());
    }
}

Haikarainen

  • Guest
Problem rendering tiles (tearing?)
« Reply #2 on: January 03, 2012, 02:32:38 pm »
This is a known issue, using the search function would give help.

Solution if you want smooth, floatingpoint movement; Cache the tiles! Create new textures based off your tilemap constricted to the dimensions of the tile, and set your sprite to those textures instead of your tilemap.

Generate the cache on startup.

jmcmorris

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Problem rendering tiles (tearing?)
« Reply #3 on: January 03, 2012, 09:05:23 pm »
Hey thanks guys for the response. I did search around but I must have been using the wrong keywords. I was starting to suspect this was a floating point problem given the infrequency and that it only happens while the views are moving.

@omnomasaur
Thanks I will try this later when I get home.

@Haikarainen
I'm curious how making each tile have it's own texture differs from using the tilemap texture and setting the sprite's subrect. Could you expand on this please?

Thanks again guys. :)

EDIT:
Unfortunately what @omnomasaur suggested doesn't do the trick. I'm going to try out what @Haikarainen suggested now.

Haikarainen

  • Guest
Problem rendering tiles (tearing?)
« Reply #4 on: January 04, 2012, 07:09:11 am »
Quote from: "jmcmorris"
@Haikarainen
I'm curious how making each tile have it's own texture differs from using the tilemap texture and setting the sprite's subrect. Could you expand on this please?


The tearing comes from when you set the subrect of the sprite using floats, OR if you set it with int and then position the sprite/view using float. It has to do with how OpenGL sets up a perspective and renders quads I belive.

Anyway, caching them worked out for me, since my project needs floats for movement. You basically create a new sf::Texture(2.0) or sf::Image(1.6) for each tile, and create it from a subrect of your tileset.

jmcmorris

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Problem rendering tiles (tearing?)
« Reply #5 on: January 04, 2012, 11:39:02 am »
Doing what you suggested appears to have resolved the problem. Now I just need to optimize my solution some. Thanks for the help Haikarainen. I appreciate it!

BlueMagic

  • Newbie
  • *
  • Posts: 49
    • View Profile
Problem rendering tiles (tearing?)
« Reply #6 on: January 27, 2012, 08:42:21 pm »
Hey, I've been having the same problem. I'm using 2.0's vertex array for this, so your solution wouldn't work. Any other solution available?

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Problem rendering tiles (tearing?)
« Reply #7 on: January 28, 2012, 02:05:29 pm »
Scale your viewport accordingly, then round your coordinates to full pixels.

For my own project, I switched strategies when drawing tiles (organized as "blocks"): I draw only one quad and draw the single tiles on it using a pixel shader which solves the tiling issue as well as allowing some neat tricks (like animated water or background distorting ice blocks).

BlueMagic

  • Newbie
  • *
  • Posts: 49
    • View Profile
Problem rendering tiles (tearing?)
« Reply #8 on: January 28, 2012, 03:26:47 pm »
Quote from: "Mario"
Scale your viewport accordingly, then round your coordinates to full pixels.

For my own project, I switched strategies when drawing tiles (organized as "blocks"): I draw only one quad and draw the single tiles on it using a pixel shader which solves the tiling issue as well as allowing some neat tricks (like animated water or background distorting ice blocks).


What do you mean by scaling the viewport accordingly? If I round the coordinates I get jerky movement because my character's position is given also by float numbers.

Also nice idea using a pixel shader. I might end up adding something like that to get nice looking water.

BlueMagic

  • Newbie
  • *
  • Posts: 49
    • View Profile
Problem rendering tiles (tearing?)
« Reply #9 on: January 29, 2012, 08:00:45 pm »
Quote from: "BlueMagic"
Hey, I've been having the same problem. I'm using 2.0's vertex array for this, so your solution wouldn't work. Any other solution available?


Anyone? Help is very much appreciated. Here's a picture for reference, even though everyone knows what the problem looks like:

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Problem rendering tiles (tearing?)
« Reply #10 on: January 31, 2012, 12:33:16 pm »
Scaling the viewport: E.g. you'd like to show 320x240 (upscaled) pixels on screen. Set the viewport's width/height to exactly these values. Then, when moving the camera's center (or drawing anything), round the coordinates and everything should align fine.

BlueMagic

  • Newbie
  • *
  • Posts: 49
    • View Profile
Problem rendering tiles (tearing?)
« Reply #11 on: January 31, 2012, 03:50:11 pm »
The size of the view is exactly the quantity of pixels I want to show onscreen. The viewport size, if I am not mistaken, is only given by a float number that goes from 0 to 1, and in the case that it is in windowed mode, it is always filling the window.

I can't round the coordinates when moving the camera because I will inevitably get jerky movement. It will happen something like this, if I round the number:

1-The character is in the center of the screen
2-The character moves, but not enough so that the view has to move 1 round unit.
3-The character keeps moving and the view will change because he moved enough so that the view has to move 1 round unit.
4- 2 again.

The difference of the position of the camera and the character between 2 and 3 gives the feeling of jerky, bumpy movement, and it sucks that there's practically no workaround.

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Problem rendering tiles (tearing?)
« Reply #12 on: January 31, 2012, 06:34:03 pm »
How about putting the whole tile map into one vertex array? This way it should be easy to ensure they really match and connect exactly to each other?

BlueMagic

  • Newbie
  • *
  • Posts: 49
    • View Profile
Problem rendering tiles (tearing?)
« Reply #13 on: January 31, 2012, 07:10:06 pm »
I am already using a vertex array the size of the window to draw only the tiles that appear on the screen (and an extra row that you don't see, if I recall correctly).

EDIT:It still happens if I draw them all in one big vertex array, even the ones I don't need.

BlueMagic

  • Newbie
  • *
  • Posts: 49
    • View Profile
Problem rendering tiles (tearing?)
« Reply #14 on: February 01, 2012, 12:05:05 am »
Well, someone get lucasnvc (http://www.sfml-dev.org/forum/viewtopic.php?t=5952&start=0) a prize or something.
When rendering the tiles, if I substract 0.0075 from the right and bottom coordinates for TexCoords, it renders nicely and with no weird lines.

Here's what the relevant part of the code looks like:

Code: [Select]

for (x=0;x<mapw;x++){
     for (y=0;y<maph;y++){
         
         //Set vertex position
         //tx and ty are the coordinates in the tetxure of the tile that we are referring to in the current iteration of the loop.
          map[current + 0].TexCoords = sf::Vector2f( (tx + 0)* tileWidth, (ty + 0)* tileHeight);
          map[current + 1].TexCoords = sf::Vector2f( (tx + 0)* tileWidth, (ty + 1)* tileHeight-0.0075);
          map[current + 2].TexCoords = sf::Vector2f( (tx + 1)* tileWidth-0.0075, (ty + 1)* tileHeight-0.0075);
          map[current + 3].TexCoords = sf::Vector2f( (tx + 1)* tileWidth-0.0075, (ty + 0)* tileHeight);
      }
}


I am currently still testing but so far so good.