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

Author Topic: Line artifacts when drawing tilemap  (Read 16963 times)

0 Members and 1 Guest are viewing this topic.

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Line artifacts when drawing tilemap
« on: July 23, 2014, 05:26:28 pm »
Hi there,

I've (successfully) implemented the tilemap example from the resources into my game engine, but I'm getting these really odd line-like artifacts in between the tiles. I've recently switched computers, and on my other computer I already had this working with the same code and resources and did not have this issue. I've already validated that all of my tile resources have no artifacts on them, I've checked my code (it's exactly the same as in the examples), I've tried enabling vsync and texture smoothing with no avail, and I've looked around the forums for similar issues. On some posts I've seen people adding odd values to the texture coordinates like 0.375 and I also tried that, but it didn't work as well. I've attached a photo of my issue.

Thanks!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11006
    • View Profile
    • development blog
    • Email
AW: Line artifacts when drawing tilemap
« Reply #1 on: July 23, 2014, 05:46:13 pm »
Did you make sure that your tiles are at integer position and the view isn't changed?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

BaneTrapper

  • Full Member
  • ***
  • Posts: 213
  • Do you even see this, i dont need it.
    • View Profile
    • Email
Re: AW: Line artifacts when drawing tilemap
« Reply #2 on: July 23, 2014, 06:06:55 pm »
Did you make sure that your tiles are at integer position and the view isn't changed?
As eXpl0it3r said, its because your tiles are not at rounded position. when setting position do std::floor(position)
BaneTrapperDev@hotmail.com Programing, Coding
Projects: Not in development(unfinished/playable):
http://en.sfml-dev.org/forums/index.php?topic=11073.msg76266#msg76266
UP and in Development: The Wanderer - Lost in time
http://en.sfml-dev.org/forums/index.php?topic=14563.0

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #3 on: July 23, 2014, 08:30:36 pm »
Ok, now I'm doing this to set position:

quad[0].position = sf::Vector2f(std::floor(topLeft.x), std::floor(topLeft.y));
quad[1].position = sf::Vector2f(std::floor(topRight.x), std::floor(topRight.y));                                        quad[2].position = sf::Vector2f(std::floor(downLeft.x), std::floor(downLeft.y));                                        quad[3].position = sf::Vector2f(std::floor(downRight.x), std::floor(downRight.y));

It hasn't done anything. I double checked to make sure each quad's position is an integer, which it is. The view isn't changing at all either.

BaneTrapper

  • Full Member
  • ***
  • Posts: 213
  • Do you even see this, i dont need it.
    • View Profile
    • Email
Re: Line artifacts when drawing tilemap
« Reply #4 on: July 23, 2014, 10:49:51 pm »
Post minimal example that reproduces the error.
BaneTrapperDev@hotmail.com Programing, Coding
Projects: Not in development(unfinished/playable):
http://en.sfml-dev.org/forums/index.php?topic=11073.msg76266#msg76266
UP and in Development: The Wanderer - Lost in time
http://en.sfml-dev.org/forums/index.php?topic=14563.0

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #5 on: July 24, 2014, 12:01:29 am »
void load(const std::string& tileSet, sf::Vector2u tileSize, int* tiles,
                        unsigned int width, unsigned int height)
                {
                        m_tileset.loadFromFile(tileSet);

                        m_vertices.setPrimitiveType(sf::Quads);
                        m_vertices.resize(width * height * 4);

                        for (unsigned int i = 0; i < width; ++i)
                        {
                                for (unsigned int j = 0; j < height; ++j)
                                {
                                        int tileNumber = tiles[i + j * width];

                                        sf::Vector2f topLeft(i * tileSize.x, j * tileSize.y);
                                        sf::Vector2f topRight((i + 1) * tileSize.x, j * tileSize.y);
                                        sf::Vector2f downLeft((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                                        sf::Vector2f downRight(i * tileSize.x, (j + 1) * tileSize.y);

                                        sf::FloatRect rect(topLeft.x, topLeft.y, topRight.x - topLeft.x, downLeft.y - topLeft.y);

                                        Tile tile(rect, tileNumber);

                                        m_tiles.push_back(tile);

                                        //Find the position in the tileset texture
                                        int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                                        int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);

                                        sf::Vertex* quad = &m_vertices[(i + j * width) * 4];

                                        //Define its 4 corners
                                        quad[0].position = sf::Vector2f(std::floor(topLeft.x), std::floor(topLeft.y));
                                        quad[1].position = sf::Vector2f(std::floor(topRight.x), std::floor(topRight.y));
                                        quad[2].position = sf::Vector2f(std::floor(downLeft.x), std::floor(downLeft.y));
                                        quad[3].position = sf::Vector2f(std::floor(downRight.x), std::floor(downRight.y));

                                        //Define its 4 texture coordinates
                                        quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                                        quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                                        quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                                        quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
                                }
                        }
                }

That's the entirety of my drawing code.

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #6 on: July 24, 2014, 12:17:52 am »
I fixed similiar problem by using 1 pixel margin around tiles in spritesheet. For some reason GPU was pulling pixels from outside of the texcoords.
SFML.Utils - useful extensions for SFML.Net

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Line artifacts when drawing tilemap
« Reply #7 on: July 24, 2014, 01:27:12 am »
That's the entirety of my drawing code.
We could use a complete and minimal example so others can compile it and test it for their selves.

Does your texture have smooth turned on?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

The Terminator

  • Full Member
  • ***
  • Posts: 224
  • Windows and Mac C++ Developer
    • View Profile
Line artifacts when drawing tilemap
« Reply #8 on: July 24, 2014, 02:04:31 pm »
That's the entirety of my drawing code.
We could use a complete and minimal example so others can compile it and test it for their selves.

The code is exactly the same as the tutorials. Exactly the same.

Quote
Does your texture have smooth turned on?

He's already said that texture smoothing didn't help.
Current Projects:
Technoport

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #9 on: July 24, 2014, 04:17:14 pm »
I fixed similiar problem by using 1 pixel margin around tiles in spritesheet. For some reason GPU was pulling pixels from outside of the texcoords.

I tried this, but it made the problem even more apparent with even larger black lines.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Line artifacts when drawing tilemap
« Reply #10 on: July 24, 2014, 08:03:32 pm »
my drawing code.
complete and minimal example
The code is exactly the same as the tutorials. Exactly the same.
That code might be but it's not complete. It's the rest of the code we need to see (especially since if that code is identical to the tutorials, we know it works).

Quote
Does your texture have smooth turned on?
I missed that, or forgot that it was mentioned by the time I'd read the entire thread. Sorry, my error.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #11 on: July 25, 2014, 10:50:03 pm »
I'm really stumped, and I can't figure out what the issue is. Does anyone else have any ideas?

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Line artifacts when drawing tilemap
« Reply #12 on: July 25, 2014, 11:01:04 pm »
This is a shot in the dark; but if your textures are not using "powers of two" dimentions, that might be it. Older graphics cards or old drivers may not deal properly with such textures. So, if your texture dimensions are not "power of two",  try making them so.

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #13 on: July 25, 2014, 11:49:20 pm »
This is a shot in the dark; but if your textures are not using "powers of two" dimentions, that might be it. Older graphics cards or old drivers may not deal properly with such textures. So, if your texture dimensions are not "power of two",  try making them so.

The tiles are 16x16, and I thought it was a driver issue too. I'm running a Nvidia GTX 760, and I tested it on my brother's laptop which has an intel hd 3000. He had the exact same issue, so it's not a driver issue.

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #14 on: July 28, 2014, 05:37:37 pm »
Ok, here's the entirety of all of my relevant code:

Player.hpp

class Player : public Entity
        {
        public:
                typedef std::shared_ptr<Player> Ptr;

                static Ptr create(const std::string& id = "player") { Ptr temp(new Player(id)); return temp; }

                void handleCollision();

                void move(const sf::Vector2f& offset);

                virtual void update(sf::Time dt);

                void draw(sf::RenderTarget& target, sf::RenderStates states) const;

        private:
                Player(const std::string& id = "player", bool active = true);

                sf::Texture m_texture;
                sf::Sprite m_sprite;

                sf::Vector2f m_viewArea;

                bool nextPosValid(const sf::Vector2f& offset);
                bool rectOverlapsTile(const sf::FloatRect& rect);
        };

Player.cpp

        Player::Player(const std::string& id, bool active) :
                m_viewArea(sf::Vector2f(100, 100))
        {
                m_texture.loadFromFile("Resources/player.png");
                m_sprite.setTexture(m_texture);
                m_sprite.setPosition(350, 300);

                registerAttribute("renderable", new bool(true));
                registerAttribute("health", new int(20));

                SceneManager::getView().setCenter(std::floor(350), std::floor(300));
                SceneManager::getView().setSize(m_viewArea);
        }

        bool Player::nextPosValid(const sf::Vector2f& offset)
        {
                sf::Vector2f offsettedPos(std::floor(m_sprite.getPosition().x + offset.x), std::floor(m_sprite.getPosition().y + offset.y));

                //The bounding rectangle of the future player
                sf::FloatRect rect(offsettedPos, sf::Vector2f(std::floor(m_sprite.getGlobalBounds().width), std::floor(m_sprite.getGlobalBounds().height)));

                if (SceneManager::getWorld().getCurrentCell()->getTileMap().collidesWithType(2, rect))
                        return false;

                return true;
        }

        void Player::move(const sf::Vector2f& offset)
        {
                m_sprite.move(offset);
                SceneManager::getView().move(offset);
        }

        void Player::update(sf::Time dt)
        {
                if (InputManager::isActive(User_Input::UPHOLD))
                {
                        if (nextPosValid(sf::Vector2f(0, -100 * dt.asSeconds())))
                                move(sf::Vector2f(0, -100 * dt.asSeconds()));
                }

                if (InputManager::isActive(User_Input::LEFTHOLD))
                {
                        if (nextPosValid(sf::Vector2f(-100 * dt.asSeconds(), 0)))
                                move(sf::Vector2f(-100 * dt.asSeconds(), 0));
                }

                if (InputManager::isActive(User_Input::DOWNHOLD))
                {
                        if (nextPosValid(sf::Vector2f(0, 100 * dt.asSeconds())))
                                move(sf::Vector2f(0, 100 * dt.asSeconds()));
                }

                if (InputManager::isActive(User_Input::RIGHTHOLD))
                {
                        if (nextPosValid(sf::Vector2f(100 * dt.asSeconds(), 0)))
                                move(sf::Vector2f(100 * dt.asSeconds(), 0));
                }

                if (InputManager::isActive(User_Input::PPRESS))
                {
                        getAttribute<int>("health") -= 5;

                        std::cout << "Player health is now: " << getAttribute<int>("health") << std::endl;
                }

                if (InputManager::isActive(User_Input::VHOLD))
                {
                        if (SceneManager::getView().getSize().x < 300 ||
                                SceneManager::getView().getSize().y < 300)
                                SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x + 0.5, SceneManager::getView().getSize().y + 0.5));
                }

                else if (InputManager::isActive(User_Input::IHOLD))
                {
                        if (SceneManager::getView().getSize().x >= 100 ||
                                SceneManager::getView().getSize().y >= 100)
                                SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x - 0.5, SceneManager::getView().getSize().y - 0.5));
                }

                if (getAttribute<int>("health") <= 0)
                        setAttribute("renderable", new bool(false));

                setPosition(m_sprite.getPosition());
                setBounds(m_sprite.getGlobalBounds());
        }

        void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
                target.draw(m_sprite, states);
        }

Tilemap.hpp

        class TileMap : public sf::Drawable, public sf::Transformable
        {
        public:
                struct Tile
                {
                        Tile(const sf::FloatRect& bounds, int tileType) : bounds(bounds), tileType(tileType) {};

                        sf::FloatRect bounds;
                        int tileType;
                };

                void load(const std::string& tileSet, sf::Vector2u tileSize, int* tiles,
                        unsigned int width, unsigned int height)
                {
                        m_tileset.loadFromFile(tileSet);

                        m_vertices.setPrimitiveType(sf::Quads);
                        m_vertices.resize(width * height * 4);

                        for (unsigned int i = 0; i < width; ++i)
                        {
                                for (unsigned int j = 0; j < height; ++j)
                                {
                                        int tileNumber = tiles[i + j * width];

                                        sf::Vector2f topLeft(i * tileSize.x, j * tileSize.y);
                                        sf::Vector2f topRight((i + 1) * tileSize.x, j * tileSize.y);
                                        sf::Vector2f downLeft((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                                        sf::Vector2f downRight(i * tileSize.x, (j + 1) * tileSize.y);

                                        sf::FloatRect rect(topLeft.x, topLeft.y, topRight.x - topLeft.x, downLeft.y - topLeft.y);

                                        Tile tile(rect, tileNumber);

                                        m_tiles.push_back(tile);

                                        //Find the position in the tileset texture
                                        int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                                        int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);

                                        sf::Vertex* quad = &m_vertices[(i + j * width) * 4];

                                        //Define its 4 corners
                                        quad[0].position = sf::Vector2f(std::floor(topLeft.x), std::floor(topLeft.y));
                                        quad[1].position = sf::Vector2f(std::floor(topRight.x), std::floor(topRight.y));
                                        quad[2].position = sf::Vector2f(std::floor(downLeft.x), std::floor(downLeft.y));
                                        quad[3].position = sf::Vector2f(std::floor(downRight.x), std::floor(downRight.y));

                                        //Define its 4 texture coordinates
                                        quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                                        quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                                        quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                                        quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
                                }
                        }
                }

                bool collidesWithType(int tileType, const sf::FloatRect& bounds)
                {
                        for (auto& iter : m_tiles)
                        {
                                if (iter.tileType == tileType)
                                {
                                        if (bounds.intersects(iter.bounds))
                                                return true;
                                }
                        }

                        return false;
                }

        private:
                virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
                {
                        states.transform *= getTransform();
                        states.texture = &m_tileset;
                        target.draw(m_vertices, states);
                }

                sf::VertexArray m_vertices;
                sf::Texture m_tileset;

                std::vector<Tile> m_tiles;
        };

As you can see, I tried using std::floor on my views and my tiles, but unfortunately nothing has been working so far.