5

I have one image: background.png. How to create continuously repeating scrolling background image with android OpenGL ES or AndEngine library or other technology you know?

Example:
moving cloud

Currently, I use two-adjacent-image technique. I load image (background.png) two times and I put them adjacently, then I move them. So it looks like just one image scrolling continuously.

But, somehow I think there might be a better solution with just using one image instance. Anyone can share?

UPDATE:
For the one who curious, this is the two-adjacent-image code (using AndEngine library):

movingBackgroundSprite.registerEntityModifier(new LoopEntityModifier(
    new MoveYModifier(10, -CAMERA_HEIGHT, 0)));     
movingBackgroundSprite2.registerEntityModifier(new LoopEntityModifier(
    new MoveYModifier(10, 0, CAMERA_HEIGHT)));

Above code is about making a background image repeatedly & vertically scrolling from top to bottom.

Note:
* movingBackgroundSprite is a Sprite class that load the background.png image. You can see there are two instances of the background Sprite.
* registerEntityModifier -> apply modifier/behaviour for the Sprite
* LoopEntityModifier -> looping behaviour
* MoveYModifier -> moving behaviour by y-position. The 1st argument is the duration (you can ignore this since it's nothing to do with the question), the 2nd argument is the Source-Y position, the 3rd argument is the Destination-Y position.
* CAMERA_HEIGHT -> constant that define the height of background image.

Community
  • 1
  • 1
null
  • 8,669
  • 16
  • 68
  • 98

2 Answers2

5

If you've set glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) (which I think is the default anyway) you can just draw a fullscreen quad and increment the s texture coordinate in small steps (it works vertically too, if you want that).

Values greater than 1.0 will wrap to the left of the texture, nothing extra needed. And, no two draw calls needed.

You didn't say whether you have ES 1.0 or 2.0, but if it's 2.0 you can pass an offset as an uniform instead and add that to the texture coordinates in a shader, which is more efficient than changing the vertex data (texcoord) every frame. Though being a once-per-frame thing, it probably does not matter in any way, it's probably just the same.

EDIT:
I don't know about AndEngine, there might be simpler, more convenient commands to draw a textured fullscreen quad... but given "OpenGL ES 1.0", using immediate mode and assuming default MVP matrix, this could look something like this as a very crude example:

glBindTexture(GL_TEXTURE_2D, cloudy_sky_texture);
glTexImage(...);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
...
float offset = 0.0f;
while(!quit)
{
    offset += 1.0f/texture_size;

    glBindTexture(GL_TEXTURE_2D, cloudy_sky_texture);

    glBegin(GL_QUADS);
        glVertex2f(-1.0f, -1.0f);
        glTexCoord2f(0.0f + offset, 0.0f);
        ...
        glVertex2f(1.0f,  1.0);
        glTexCoord2f(1.0f + offset, 1.0f);
    glEnd();

    DrawForegroundStuff();
}

Some lines are omitted for brevity, immediate mode is not nice, and there's plenty of room for optimization, but the principle should be clear. You really just draw one quad and increment the s component of the texture coordinates.

Damon
  • 67,688
  • 20
  • 135
  • 185
  • Hi, could you provide a little bit of sample code? I'm using OpenGL ES 1.0. – null Apr 19 '12 at 12:27
  • Hi, thx for your code example. I really appreciate it. Probably it will take a lot of times for me to understand the code and try it with AndEngine. – null Apr 23 '12 at 09:03
  • What happens if the float value wraps? – paulm Nov 22 '13 at 11:59
  • 1
    @paulm: Seeing how the increment is rather small (something like 1/256 or 1/512) it will be centuries before that happens. But your objection is of course generally correct. A bigger concern would be precision slowly decreasing as the float value gets bigger and bigger (but that, too, would only become visible after many weeks of running). Texture coordinates go from 0.0 to 1.0 and wrap around, so effectively 0.3, 1.3, and 15.3 are all the same thing. One could thus add something like `if(offset > 10.0f) offset -= 9.0f` to always force the float value being in a small, precise range. – Damon Nov 22 '13 at 12:33
  • Or I guess just normalize the value back to 0.0 - 1.0? Then it can run forever without breaking – paulm Nov 22 '13 at 13:50
  • @paulm: Then you will likely not get the desired image. "Normalizing" the value back will mean subtracting multiples of 1.0 until the value is between 0.0 and 1.0. Which means that the left and the right edge now have the same texture coordinate (since they differ by 1.0), and the interpolator will thus give every fragment the same texture coordinate. So every pixel gets the same color. Note that while 0.6 and 1.6 are "the same" texture coordinate (i.e. the same texel), they are quite different values for the interpolator! – Damon Nov 22 '13 at 13:58
  • Thanks, @Damon. This worked well for me (OpenGL ES 2). `glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)` does seem to be the default. – async Feb 08 '14 at 14:55
1

You might have found answers but just in case if other Andengine game developers have confusion in making background scrollable, I would suggest to use AutoParallaxBackground as it is easy and efficient to use.

To implement AutoParallaxBackground follow the steps:

1)Declare and initialise BitmapTextureAtlas and TextureRegion.

private BitmapTextureAtlas mAutoParallaxBackgroundTexture;
private TextureRegion background_region;
mAutoParallaxBackgroundTexture = new BitmapTextureAtlas(1024, 1024,TextureOptions.DEFAULT);
background_region= BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mAutoParallaxBackgroundTexture, this,"backgroundImg.png", 0, 0);

2)Declare and initialise background sprite and AutoParallaxBackground.

final AutoParallaxBackground auto_background = new AutoParallaxBackground(0, 0, 0, 5);         
final Sprite background_sprite = new Sprite(0,0, this.background_region,vbom);

3)Add background_sprite as parallax entity to AutoParallaxBackground object.

auto_background.attachParallaxEntity(new ParallaxEntity(1.7f,background_sprite));

4)Finally, set AutoParallaxBackground object as your scene background.

your_scene.setBackground(auto_background);

Hope this will later help somebody.

Crawler
  • 1,988
  • 3
  • 21
  • 42