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

Author Topic: [Resolved] Isometric algorithm is slightly off by a few pixels.  (Read 2825 times)

0 Members and 1 Guest are viewing this topic.

Honor

  • Newbie
  • *
  • Posts: 5
    • View Profile
[Resolved] Isometric algorithm is slightly off by a few pixels.
« on: September 17, 2016, 06:33:00 am »
Am intently following the vertex-array tutorial on the website, am fixing the algorithm to sort my tiles isometrically. My tiles appear to draw good, but on closer inspection the pixels are sliiightly off. Not so sure what in my algorithm is causing it to be off, I've tried toying with it for several hours with no luck.

Here is an image of the result, including a zoomed/enhanced image of the alignment.

(click to show/hide)

Tiles are exactly 34x18 (WIDTHxHEIGHT) chosen randomly from this tileset:
(click to show/hide)

The load function is correctly taking the appropriate arguments:
tileMap.load("data/gfx/tiles/1.png", sf::Vector2u(34, 18), map, 16); // map is the std::map which contains a std::pair as the key to access the map data at a coordinate.


bool load(const std::string& tileset, sf::Vector2u tileSize, std::map<std::pair<int, int>, int> map, unsigned int size)
{
        // to ensure map width/height are the same height
        unsigned int width = size, height = size;

        // load the tileset texture
        if (!m_tileset.loadFromFile(tileset))
                return false;

        // resize the vertex array to fit the level size
        m_vertices.setPrimitiveType(sf::Quads);
        m_vertices.resize(width * height * 4);

        // Offset to draw more toward the center of the screen, otherwise stuff gets cut off.
        int offset_x = ((width/2) * tileSize.x) * 1.2;
        int offset_y = (height/2) * 1.2;

        for (unsigned int i = 0; i < width; ++i)
        {
                for (unsigned int j = 0; j < height; ++j)
                {
                        int tileNumber = map[std::make_pair(i, j)];

                        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];

                        quad[0].position = sf::Vector2f(offset_x + (j * tileSize.x / 2) - (i * tileSize.x / 2), offset_y + (i * tileSize.y / 2) + (j * tileSize.y / 2));
                        quad[1].position = sf::Vector2f(offset_x + (((j+2) * tileSize.x) / 2) - (i * tileSize.x / 2), offset_y + (i * tileSize.y / 2) + (j * tileSize.y / 2));
                        quad[2].position = sf::Vector2f(offset_x + (((j+2) * tileSize.x) / 2) - (i * tileSize.x / 2), offset_y + (((i+2) * tileSize.y) / 2) + (j * tileSize.y / 2));
                        quad[3].position = sf::Vector2f(offset_x + (j * tileSize.x / 2) - (i * tileSize.x / 2), offset_y + (((i+2) * tileSize.y) / 2) + (j * tileSize.y / 2));

                        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);
                }
        }
        return true;
}
 

Any help is greatly appreciated!



Edit: Am using a modified version of this formula I found online which achieves this projection:

tile_map[][] = [[...],...]

for (i = 0; i < tile_map.size; i++):
    for (j = tile_map[i].size; j >= 0; j--):  // Changed loop condition here.
        draw(
            tile_map[i][j],
            x = (j * tile_width / 2) + (i * tile_width / 2)
            y = (i * tile_height / 2) - (j * tile_height / 2)
        )

« Last Edit: September 19, 2016, 09:21:10 am by Honor »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Isometric algorithm is slightly off by a few pixels.
« Reply #1 on: September 17, 2016, 08:52:20 am »
Quote
My tiles appear to draw good, but on closer inspection the pixels are sliiightly off
Everything looks perfect. Can you be more precise about what's wrong?
Laurent Gomila - SFML developer

Honor

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Isometric algorithm is slightly off by a few pixels.
« Reply #2 on: September 17, 2016, 08:59:10 am »
Quote
My tiles appear to draw good, but on closer inspection the pixels are sliiightly off
Everything looks perfect. Can you be more precise about what's wrong?

The projected red lines are where the tiles should ride against, for some reason the tiles work inward as the i and j increase.
« Last Edit: September 17, 2016, 09:45:31 am by Honor »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Isometric algorithm is slightly off by a few pixels.
« Reply #3 on: September 17, 2016, 10:40:52 am »
Look at the outer edge of the zoomed in screenshot. Within a tile, the edge goes 2 to the right and 1 down, while between tiles the edge goes 1 to the right and 1 down.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: Isometric algorithm is slightly off by a few pixels.
« Reply #4 on: September 17, 2016, 10:41:31 am »
Make sure to use interger position and make sure that they are rounded correctly.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Honor

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: AW: Isometric algorithm is slightly off by a few pixels.
« Reply #5 on: September 17, 2016, 11:55:15 pm »
Make sure to use interger position and make sure that they are rounded correctly.

Don't the vertex quad positions literally require sf::Vector2<float> ? Casting an (int) in each parameter still gave me no change.

Look at the outer edge of the zoomed in screenshot. Within a tile, the edge goes 2 to the right and 1 down, while between tiles the edge goes 1 to the right and 1 down.
I feel like the obvious way to fix this is to add tiny incremental/decremental amounts to the appropriate x/y value for each tile. But that's like putting a band-aid over an issue that's only going to cause more problems down the road.

Honor

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Isometric algorithm is slightly off by a few pixels.
« Reply #6 on: September 19, 2016, 01:11:14 am »
I've found the issue. I don't think I was iterating through the tiles right for isometric. Instead of iterating 34/2 x for each tile, changing it to 36/2 worked. I also had to do - 2 for quad[1] and quad[2] to ensure the quads size was 34x18 as the graphics are.

Image result:
(click to show/hide)

The fix:
quad[0].position = sf::Vector2f(offset_x + (j * (tileSize.x + 2) / 2) - (i * (tileSize.x + 2) / 2), offset_y + (i * tileSize.y / 2) + (j * tileSize.y / 2));
quad[1].position = sf::Vector2f(offset_x + (j * (tileSize.x + 2) / 2) - ((i+2) * (tileSize.x + 2) / 2) + 2, offset_y + (i * tileSize.y / 2) + (j * tileSize.y / 2));
quad[2].position = sf::Vector2f(offset_x + (j * (tileSize.x + 2) / 2) - ((i+2) * (tileSize.x + 2) / 2) + 2, offset_y + (i * tileSize.y / 2) + (((j+2) * tileSize.y) / 2));
quad[3].position = sf::Vector2f(offset_x + (j * (tileSize.x + 2) / 2) - (i * (tileSize.x + 2) / 2), offset_y + (i * tileSize.y / 2) + (((j+2) * tileSize.y) / 2));

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);
 

Thanks to everyone who helped!