Fragment shader for game tile engine (tilemap) smooth scrolling/per-pixel offset fail

Okay, tile_types_super_texture is a row of several 16x16 tile type textures, which are the tile types. Then according to tilemap_pixels, which is a 1-tile-per-pixel representation of the visible map on screen. According to the value within the red channel, it would be that index towards the end. Think of the super texture as a linear array, where each element is 16x16 pixels big, and the red channel is the index to the element.

This worked wonderfully, but it only scrolled to every 16x16 tile, so scrolling was jumpy and not per-pixel/smooth scrolling. So I thought I would do m_viewPosition & TILE_SIZE-1, which gives me the remaining pixels which cannot align to the 16x16 grid.

However, as you can see below, where I added the - int (offset.x), and .y, instead of smoothly scrolling, it’s actually creating a sort of window blinds shutter effect, where if i move…say…8 pixels (half a tile) out, many tiles are cut in half (oddly…not all of them).

Does this have to do with using texelFetch? I was thinking about resorting back to texture2D, so that I can run on lower end hardware as well. Or am I doing something intrinsically incorrect?

#version 130
//unsupported though, isn't it? #extension GL_EXT_gpu_shader4 : enable

// for a 1600x900 screen, this results in an image of 50x100 with each pixel representing a tile
uniform sampler2D tilemap_pixels;

// a runtime generated spritesheet of all tiles we know, each tile being 16x16 (so 48x16 if there are 3 tile types)
uniform sampler2D tile_types_super_texture;

// offset (remainder of view coordinates versus tile size). to achieve per-pixel smooth scrolling
uniform vec2 offset;

//FIXME: stop hardcoding ..
ivec2 TILE_SIZE = ivec2(16, 16);

void main()
{
    ivec2 tilemap_size = textureSize(tile_types_super_texture, 0);

    ivec2 screen_coordinates = ivec2(gl_FragCoord.x, gl_FragCoord.y);

    // find the pixel (RGBA) values in the tilemap pixel representation that is what we're
    // currently interested in.
    vec4 currentPixel = texelFetch(tilemap_pixels, screen_coordinates / TILE_SIZE, 0);

    ivec2 tileCoordinate;
    tileCoordinate.x = (int(currentPixel.r * 255.0) ) * TILE_SIZE.x + (screen_coordinates.x % TILE_SIZE.x) - int(offset.x);
    tileCoordinate.y = screen_coordinates.y % TILE_SIZE.y - int(offset.y);

    vec4 tileColor = texelFetch(tile_types_super_texture, tileCoordinate, 0);

    gl_FragColor = tileColor;
}

I don’t think this is right



vec4 currentPixel = texelFetch(tilemap_pixels, screen_coordinates / TILE_SIZE, 0);

This implies that the first 16 pixels on the screen are all from the first tile - this is only true if offset.x = 0

[QUOTE=tonyo_au;1245583]I don’t think this is right



vec4 currentPixel = texelFetch(tilemap_pixels, screen_coordinates / TILE_SIZE, 0);

This implies that the first 16 pixels on the screen are all from the first tile - this is only true if offset.x = 0[/QUOTE]

oh wow, you’re absolutely right. I didn’t need the other offset, I just needed it in that. I didn’t think that would work, since there are just 1 pixels there which represent 1 tile… interesting.

updated and working wonderfully code. thanks a bunch :slight_smile:


#version 130
//unsupported though, isn't it? #extension GL_EXT_gpu_shader4 : enable

// for a 1600x900 screen, this results in an image of 50x100 with each pixel representing a tile
uniform sampler2D tilemap_pixels;

// a runtime generated spritesheet of all tiles we know, each tile being 16x16 (so 48x16 if there are 3 tile types)
uniform sampler2D tile_types_super_texture;

// offset (remainder of view coordinates versus tile size). to achieve per-pixel smooth scrolling
uniform vec2 offset;

//FIXME: stop hardcoding ..
ivec2 TILE_SIZE = ivec2(16, 16);

void main()
{
    ivec2 tilemap_size = textureSize(tile_types_super_texture, 0);

    ivec2 screen_coordinates = ivec2(gl_FragCoord.x + int (offset.x), gl_FragCoord.y - int (offset.y));

    // find the pixel (RGBA) values in the tilemap pixel representation that is what we're
    // currently interested in.
    vec4 currentPixel = texelFetch(tilemap_pixels, screen_coordinates / TILE_SIZE, 0);

    ivec2 tileCoordinate;
    tileCoordinate.x = (int(currentPixel.r * 255.0) ) * TILE_SIZE.x + (screen_coordinates.x % TILE_SIZE.x);// - int(offset.x);
    tileCoordinate.y = screen_coordinates.y % TILE_SIZE.y;// - int(offset.y);

    vec4 tileColor = texelFetch(tile_types_super_texture, tileCoordinate, 0);

    gl_FragColor = tileColor;
}

ah yes, i encountered another issue and fixed it easier than i thought…

on the app side, I just passed it a column and row 1 bigger to the pixel map…that way that will take care of borders. so x was fixed, but the bottom of the screen had a gap that was horrid and distracting since it moved. Turns out i had to offset screen coordinates by a TILE_SIZE


#version 130
//unsupported though, isn't it? #extension GL_EXT_gpu_shader4 : enable

// for a 1600x900 screen, this results in an image of 50x100 with each pixel representing a tile
uniform sampler2D tilemap_pixels;

// a runtime generated spritesheet of all tiles we know, each tile being 16x16 (so 48x16 if there are 3 tile types)
uniform sampler2D tile_types_super_texture;

// offset (remainder of view coordinates versus tile size). to achieve per-pixel smooth scrolling
uniform vec2 offset;

//FIXME: stop hardcoding ..
ivec2 TILE_SIZE = ivec2(16, 16);

void main()
{
    ivec2 tilemap_size = textureSize(tile_types_super_texture, 0);

    ivec2 screen_coordinates = ivec2(gl_FragCoord.x + int(offset.x), gl_FragCoord.y - int(offset.y) + TILE_SIZE.y);

    // find the pixel (RGBA) values in the tilemap pixel representation that is what we're
    // currently interested in.
    vec4 currentPixel = texelFetch(tilemap_pixels, screen_coordinates / TILE_SIZE, 0);

    ivec2 tileCoordinate;
    tileCoordinate.x = (int(currentPixel.r * 255.0) ) * TILE_SIZE.x + (screen_coordinates.x % TILE_SIZE.x);
    tileCoordinate.y = (screen_coordinates.y) % TILE_SIZE.y;

    vec4 tileColor = texelFetch(tile_types_super_texture, tileCoordinate, 0);

    gl_FragColor = tileColor;
}

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.