Fistandantilus282303

I need to do a 2d parallax floor sprite. (I want to closely emulate the style of an older game).

Let me explain. I have a long, short rectangular floor texture. I'm rendering it as a texture on a 2 triangle (to make a square or rectangle) set of primitives, that is normally the same size as the texture, and the upper left corner is mapped to 0,0 of the texture, and the lower right corner to 1,1, etc.

What I want to happen is when the screen scrolls to the left or right, the top line scrolls slower than the bottom line, and the lines in between scroll an appropriate amount somewhere in between.

One way I could do this would be to draw one rectangle for each pixel in the texture's height, so that each can have a different x position.

However that seems really inefficient. I've tried drawing my rectangle more like a parallelogram. But that resulted in scaling the texture instead.

I also tried changing the z, but for some reason that didn't work the way I expected. It seemed to just not draw either the top or bottom of the rectangle, instead of drawing it at a perspective.

Maybe that is because I'm using Matrix.CreateOrthographicOffCenter() to create my projection matrix, instead of CreatePerspectiveFieldOfView. I don't understand the difference though, could someone explain it or point me somewhere

Thanks.


Re: XNA Framework best way to do 2d parallax floor sprite

dczraptor

Orthogonal projection means that an object rendered 50 units away from the camera will look exactly the same an object 500 units away, at exactly the same size. Perspective will render objects in the distance smaller than objects in the foreground.




Re: XNA Framework best way to do 2d parallax floor sprite

Fistandantilus

Ok, I think I need some help converting to perspective.
I had been doing:
viewMatrix = Matrix.CreateLookAt(
new Vector3(0, 0, 1),
new Vector3(0f, 0.06f, 0),
Vector3.Up);

projectionMatrix = Matrix.CreateOrthographicOffCenter(
0 + x,
400f + x,
300f + y,
0f + y,
-10.0f, 50.0f);

worldViewProjection = viewMatrix * projectionMatrix;


And my screen was 400x300 and my quads used actual pixel values.
How do I go about using CreatePerspectiveOffCenter or something like it in this situation
Basically I want it to look exactly the same as Orthogonal except when I change the z.




Re: XNA Framework best way to do 2d parallax floor sprite

Mitch Walker - MSFT

Is there a reason you aren't using SpriteBatch Doing layers/scaling/scrolling isn't difficult (scrolling is the only thing you'd need to "code"). Don't over complicate things, try the simplest approach first.




Re: XNA Framework best way to do 2d parallax floor sprite

Fistandantilus

I was originally, but switched for a variety of reasons. Mainly vague future plans and learning the 3d methods.
I already have a working version using SpriteBatch, but it relies on drawing the graphic once for each pixel of height it has. One of the reasons I switched to the 3d methods is to do the parallax floor effect I described earlier. How would I do this with SpriteBatch

Make sure you understand what I'm wanting to do. That is draw a single sprite with it's top line (0,0 to width, 1) scrolled less than it's bottom line (0, height to width, 1) (and the rest of the lines somewhere in between).

I wanted to try doing it be changing my z on the top two vertices to be farther away than the bottom two.




Re: XNA Framework best way to do 2d parallax floor sprite

BrianOsman

Hmmm. I'm not sure this is a well-defined operation, but if I understand what you want, I think you might want textured quads where you scroll the UVs of the top two verts slower than the UVs of the bottom two verts. I assume that your sprite textures tile nicely, and you want to just loop around within that same image

Edit... Just to clarify. I think you can get the effect you want just using a simple vertex shader. Assuming that all of your sprites are simple textured quads UV-mapped with the unit square:

(0,0) - (1,0)

(0,1) - (1,1)

If you pass scroll amounts for your top/bottom into your vertex shader, you can adjust the U components: texcoord0.x = texcoord0.x + (texcoord0.y * (bottomScale-topScale)) + topScale; Roughly.





Re: XNA Framework best way to do 2d parallax floor sprite

LeeC22

Is this a scrolling floor like this....

xxxxxxxxxxxxxxxx Scrolls 1 pixel (Back of floor)
xxxxxxxxxxxxxxxx Scrolls 2 pixels
...
...
...
XXXXXXXXXX Scrolls 15 pixels
XXXXXXXXXX Scrolls 16 pixels (Front of floor)

I remember we used to this with raster interrupts setting different scroll speeds on each horizontal line, not sure if you can still do this though. Can you give us some idea of the height of the scrolling area, the number of parallax layers you need and the minimum and maximum speeds you will be using.

I'm just wondering if an animstrip would work... much like you would use for animating a person walking, but with a tile-able texture that you can lay side by side.






Re: XNA Framework best way to do 2d parallax floor sprite

Fistandantilus

That's a really interesting idea, I"m going to have to try that.
And yes, the images either tile nicely (at least horizontally) or are bigger than the screen.




Re: XNA Framework best way to do 2d parallax floor sprite

Fistandantilus

Yeah, that sounds about right. The actual number of pixels scrolled is actually calculated with a percent, but after multiplying that out, your example is right on.

I've never heard of an animstrip before, I guess that's something I should look into.
The current texture I'm playing with is 1289x39, though the ones that tile have much lower widths. The rations will probably be somewhere around the top scrolls only 75% as much as the bottom.




Re: XNA Framework best way to do 2d parallax floor sprite

Fistandantilus

Ok, I got something working with a vertex shader that looks like this:
VS_OUTPUT Transform(
float4 Position : POSITION,
float4 TextureCoordinate : TEXCOORD0 )
{
VS_OUTPUT Out = (VS_OUTPUT)0;

Out.position = mul(Position, WorldViewProj);
Out.textureCoordinate = TextureCoordinate;
Out.textureCoordinate.x += lerp(xscale.x, xscale.y, Out.textureCoordinate.y);

return Out;
}

One gotcha I ran into was that I had to do mipfilter = None; to avoid it looking funny. I'm not sure why, and only guessed it and it involved a lot of trial and error.