2
\$\begingroup\$

Alright so my question is about texture manipulation in Flash Stage3D / Context3D using AGAL for the shader language. But I'm pretty sure this could be applicable in other situations involving GPU programming.

So the goal is, if I wish to have a "scrolling" animation on a certain tile (like a tile of water), can I still have that texture packed along with all the rest of my sprite assets? Or does it have to be alone to avoid bleeding nearby assets?

From what I can understand, when the FragmentShader samples the portion of the texture offsetted during a scroll animation, any coordinates outside the desired texture will reveal incorrect nearby textures.

Some example to clarify:

  • Fluid motion (lava, water waves, acid bubbles);
  • Background motion (cloud, trees, houses);
  • Directional indicators (lines on a conveyor belt, race-circuit dash regions);

Do I need to use some extra operations to wrap the texture if it tries to sample beyond a certain point? How could those constraints be defined / transferred to the FragmentShader?

- UPDATE -

To clarify, I would like to scroll only on 1 single tile that would be part of a SpriteSheet / TextureAtlas (meaning, mixed with other existing sprites part of a game / project).

Imagine you had something like this (but better artwork, of course):

enter image description here

So a 256 x 256 Texture with a "Wavy Water" tile in the top-left corner (128 x 128 in dimensions).

How would you write a shader that can scroll through ONLY the water portion to give a sense of motion without running over the adjacent textures (ex: faces and cars).

How would you handle situations where the Quad is much larger than the texture and could repeat many times as well in combination to being able to scroll it?

\$\endgroup\$
6
  • \$\begingroup\$ You mean, for quads? you just want animated textures? \$\endgroup\$ Commented Jan 19, 2012 at 2:55
  • \$\begingroup\$ Yes, just quads. But I'm strictly speaking about whether it's possible to do from a SpriteSheet / TextureAtlas or not. \$\endgroup\$ Commented Jan 19, 2012 at 11:59
  • \$\begingroup\$ I'm pretty sure it is! I dont know flash very well, but if you want, i can try post a answer for opengl, that should not be too different. \$\endgroup\$ Commented Jan 19, 2012 at 12:05
  • \$\begingroup\$ For sure! Yeah they are somewhat identical so I'm sure I could port your answer to AGAL. I think it would require defining some bounds to do a 'modulo' of where the texture should repeat? Anyways, that's just a guess! \$\endgroup\$ Commented Jan 19, 2012 at 16:04
  • \$\begingroup\$ I guess you want something like shown in this video, but the texture is coming from a texture-atlas and isn't a texture on its own? \$\endgroup\$
    – bummzack
    Commented Jan 19, 2012 at 16:57

2 Answers 2

1
\$\begingroup\$

As you've asked me, here's my short OpenGL answer. Might not be fully optimized, just sketching something for you now.

Lets assume you have your texture:

class Texture
{
    Int2 size;
}

And you have your quad:

class Quad
{
    Float3[4] vertices;
    Int2[4] iuvs;
    Float2[4] uvs;
    Texture texture;
}

Float 3 is:

class Float3
{
    float x, y, z;
}

Float 2 is:

class Float2
{
    float u,v;
}

Int2 is: class Int2 { int w, h; }

Lets throw up some theory of what we'll do.

As you know, in UV coordinates, 0 mean the the beginning of a coordinate, 1 mean the final.

So, 0.5, 0.5 will take half of your texture and stretch it on your quad. 1.0, 1.0 will take your full texture and stretch it on your quad.

Assume our texture size is 800x50. And our quad is positioned at 0,0 and its size is 50x50.
So vertices 1 = (0,0,0)
vertice 2 = (50,0,0)
vertice 3 = (50,50,0)
vertice 4 = (0,50,0)

That should be nothing new to you.

And we want the quad to take the relative part of the texture. So lets set the iuv to 50x50

quad.iuvs = Int2(50, 50);

The iuvs i'm just wanting to store it.

Lets make the uvs of the quad take the texture size of the actual quad. So divide to reach the exact size. uv 1 is 0 / 800, 0 / 50 -> (0, 0)
uv 2 is 50 / 800, 0 / 50 -> (0.0625, 0)
uv 3 is 50 / 800, 50 / 50 -> (0.0625, 1)
uv 4 is 0 / 800, 50 / 50 -> (0, 1)

That give us a function!

Quad::SetUV()
{
    for(int i = 0; i < 4; i++)
    {
        uvs[i] = Float2(iuv[i].w / texture.size.w, iuv[i].h / texture.size.h);
    }
}

Easy enough to make your quad get the first 50x50 of the texture :D

Now comes the tricky part!

As you can see, the texture width is much higher than the quad width. So lets see what we can do.

Scroll through an entire texture

On your quad, just call every frame

ScrollW()
{
    if(iuv[1].w >= texture.size.w)
    {
        iuv[0] = Int2(0, 0);
        iuv[1] = Int2(vertices[2].x, 0);
        iuv[2] = Int2(vertices[2].x, vertices[2].y);
        iuv[3] = Int2(0, vertices[2].y);
    }
    else
    {
        foreach(Int2 i in iuv)
        {
            i.w++;
        }
    }
    setUV();
}

Done! If the uv is covering a valid area of the texture, scroll right. If its alread on the final of the texture, go to start!

Now should be easy to implement others, as scroll as tiles of fixed size, etc.

\$\endgroup\$
6
  • 2
    \$\begingroup\$ I'm quite sure that's not what the OP wanted. You're telling him how to show different animation-frames which are located at different UV coordinates. The way I understood the question is how to have a single frame within the sprite sheet and create the effect of animation by moving the same texture region over the quad. AFAIK this would only be possible with a shader that offsets/wraps the texels. \$\endgroup\$
    – bummzack
    Commented Jan 19, 2012 at 16:45
  • \$\begingroup\$ Impressive! I'll go through it a few times to fully digest and be able to apply this in AGAL. Thanks a lot @Gtoknu! \$\endgroup\$ Commented Jan 19, 2012 at 16:50
  • \$\begingroup\$ True @bummzack, however I think this is a good step in the right direction. \$\endgroup\$ Commented Jan 19, 2012 at 16:51
  • \$\begingroup\$ @bigp If you're packing different animation frames in your sprite-sheet and want to display them as an animation, then yes, this answer should help you. Otherwise not so much... maybe you should clarify what you want to do in your question then. \$\endgroup\$
    – bummzack
    Commented Jan 19, 2012 at 16:54
  • \$\begingroup\$ @bummzack, I've added an image as a visual aid to my question. Hope that clarifies it up. So it's not seperate animation frames, but rather ONE tile that would be scrolling pixel-by-pixel in any given direction (horizontally, vertically, diagonally). \$\endgroup\$ Commented Jan 19, 2012 at 17:41
0
\$\begingroup\$

Here is the idea & explanation behind how I created the tile scrolling UVs:

Making Scrollable Tiles with UV Offsets in Stage3D and AGAL

Featured Image

Basically, it involves creating a VertexBuffer filled with Vertex-Constant IDs to refer to when the vertex-shader executes and passes data to the fragment-shader. Depending how you set it up, there can be limitations as to how many tiles are scrolling in one draw pass, but should still be more than enough for most tile scrolling games / applications.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .