Problem with Atlas images and blitting to non-integer coordinates

26 views
Skip to first unread message

bobmitch

unread,
Apr 10, 2009, 2:54:23 AM4/10/09
to pyglet-users
When blitting textureatlas images to screen with non-integer
coordinates (really necessary for visually appealling and smooth
scrolling/movement) there are sampling artifacts from adjacent
textures in the atlas.
There should perhaps be an option to have the atlas addition algorithm
leave a 1 pixel, zeroed alpha channel border around each sub-texture?

The following code shows this:
nb.
ball.png = small png with alpha
other.png = png with pixels covering whole area (ie. no alpha at
edges)




from pyglet import image
from pyglet import window
from pyglet.gl import *

# Set these to the size of your background image
win = window.Window(width=768, height=768)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)


# Set these paths to a couple of graphics
atlas = pyglet.image.atlas.TextureAtlas (width=1024, height=1024)
ball = image.load('ball.png')
ball_atlas = atlas.add (ball)
other = image.load('other.png')
other_atlas = atlas.add (other)
background = image.load('space.jpg')

ball_coords = [0,0]
ball_velocity = [0.334545,0.25345]

while not win.has_exit:
win.dispatch_events()

ball_coords[0] += ball_velocity[0]
ball_coords[1] += ball_velocity[1]

if ball_coords[0] > win.width - ball.width or ball_coords[0] < 0:
ball_velocity[0] = -ball_velocity[0]
if ball_coords[1] > win.height - ball.height or ball_coords[1] <
0:
ball_velocity[1] = -ball_velocity[1]

win.clear()
background.blit(0, 0)
ball.blit(*ball_coords)
ball_atlas.blit (ball_coords[0]+45, ball_coords[1])
win.flip()

Greg Ewing

unread,
Apr 10, 2009, 7:20:11 AM4/10/09
to pyglet...@googlegroups.com
bobmitch wrote:
> When blitting textureatlas images to screen with non-integer
> coordinates (really necessary for visually appealling and smooth
> scrolling/movement) there are sampling artifacts from adjacent
> textures in the atlas.

To prevent that you need to adjust the texture coordinates
so they start half a texel in from the edges of the
subtexture.

E.g. if your subtexture is 100x100, then you use texture
coordinates (0.5, 0.5, 99.5, 99.5).

--
Greg

bobmitch

unread,
Apr 10, 2009, 7:42:25 AM4/10/09
to pyglet-users
Thanks for the tip Greg - I will give it a go tonight.
It would be nice if this could be achieved by passing a flag to the
add function of the textureatlas object, ie:

sprite_a = atlas.add (sprite_image, border=True)

Rather than having to set a 12-tuple every time I generate a texture
region.

Cheers.

Casey Duncan

unread,
Apr 11, 2009, 10:48:18 AM4/11/09
to pyglet...@googlegroups.com

Unfortunately it's not quite that simple, since texture coordinates do
not map directly to texels -- the coordinate range for the entire
texture is 0.0-1.0 regardless of texture size. To figure out the width
of "half a texel" you'll need to calculate it based on the size of the
texture. Something like this:

half_texel_height = 0.5 / texture.height
half_texel_width = 0.5 / texture.width

You could then offset your texture coordinates based on those half texel sizes.

-Casey

Then correct the "full" texture coordinates based on

bobmitch

unread,
Apr 11, 2009, 12:01:14 PM4/11/09
to pyglet-users
Ok, so I wrote a quick function than can be called with a texture
region (as returned by atlas.add) as a parameter.
This will automatically tweak the texture coordinates so that nearby
textures in the atlas aren`t sampled while filtering.
Hope somebody else finds this useful.


def tex_border (tex):
""" takes a pyglet texture/region and insets the texture coordinates
by half a texel
allowing for sub-pixel blitting without interpolation with nearby
regions within
same texture atlas """
coord_width = tex.tex_coords[3] - tex.tex_coords[0]
coord_height = tex.tex_coords[4] - tex.tex_coords[1]
x_adjust = (coord_width / tex.width) / 2.0 # get tex coord half texel
width
y_adjust = (coord_height / tex.height) / 2.0 # get tex coord half
texel width
# create new 12-tuple texture coordinate
tex.tex_coords = ( tex.tex_coords[0]+x_adjust, tex.tex_coords
[1]+y_adjust, 0,
tex.tex_coords[3]-x_adjust, tex.tex_coords[4]+y_adjust, 0,
tex.tex_coords[6]-x_adjust, tex.tex_coords[7]-y_adjust, 0,
tex.tex_coords[9]+x_adjust, tex.tex_coords[10]-y_adjust, 0)


atlas = pyglet.image.atlas.TextureAtlas (width=1024, height=1024)
pic = pyglet.image.load('bug.png')
bug_tex = atlas.add (small_red_bug_pic)
tex_border (bug_tex)
Reply all
Reply to author
Forward
0 new messages