Sign in to follow this  
Dookie

Can't find a simple Pseudo-3D algorithm

Recommended Posts

Hello! I'm working on a 2D game using Direct3D quad primitives and it's coming along great. Now I'm working on a pseudo-3D bonus round and need some help... I call it 'pseudo-3D' because all that will be happening is the flat sprite-like game objects will be scaling as they move toward the player. The x/y coordinates will scale in relation to the distance from the player too. There won't be any 3D models used, just sprites. If you've ever played the great old DOS game Wing Commander 1 or 2 then you know exactly what I'm talking about. The camera will never turn to face a new direction, but it may strafe left/right/up/down. The max distance will be 10000 units, but that figure is not set in stone. I thought about using something like this: transformed_x = actual_x * ((10000 - z_distance) / 10000) transformed_y = actual_y * ((10000 - z_distance) / 10000) transformed_scale = actual_scale * ((10000 - z_distance) / 10000) where 'actual_x' and 'actual_y' are the x/y coordinates of a game sprite on a 640x480 gamescreen, 'actual_scale' is the scale modifier for the sprite, and 'z_distance' is the distance the object is from the player (10000 = infinity, 0 = in your face!). Unfortunately, with this method the object movements would be too linear and not move and scale realistically at all. Anybody got any ideas? I'm shooting for simplicity, since the camera isn't going to turn or do anything fancy like that. Just plain scaling and x/y transformation. Thanks in advance for helping this poor retro game programmer. [smile]

Share this post


Link to post
Share on other sites
If your quads have pretransformed xyz coordinates, the easiest way would probably be to set up a projection matrix with some perspective transformation (like most 3D games have) and move the z coodinate from 1 (back) to 0 (front). This will take advantage of the perspective offered by the projection matrix, so it's hardware transformed and should look better than just scaling it linearly.

An alternative would be to come up with some curve to have the quads scale more visually pleasing. An simple square function might be a good fit, like this:


float zDist = ((10000 - z_distance) / 10000); // map to [0;1]
float zSquared = zDist * zDist; // still [0;1], but 'eases in' from 0

transformed_x = actual_x * zSquared
transformed_y = actual_y * zSquared
transformed_scale = actual_scale * zSquared


As luck would have it, Shawn Hargreaves recently made a blog post with some more ideas of how to put curves to good use. Hope this helps; we really need more good retro games :)

Share this post


Link to post
Share on other sites
Heeey, that looks pretty slick. I like that squared idea, remigius! My game is way too simplistic to rewrite it for 3D transformation with a projection matrix, so I'd probably have to do some major code rewrites to get traditional 3D to work. But that squared idea looks like it'll fit the bill perfectly. Unfortunately I need to work for the rest of the day (I'm a slave to the pager), so I'll give it a try hopefully tomorrow.

Thanks again for the great idea!

Share this post


Link to post
Share on other sites
I gave the 'squared' idea a shot and it looked much better than my code but still looked a little linear... So I tried this:


Quad->zScale *= (1.0f + (frameTime/4.0f));

...
...
...

float tLoc[2];

// Scale it...
// -----------
Quad->QuadScale[0] = Quad->zScale;
Quad->QuadScale[1] = Quad->zScale;

// Move it...
// ----------
tLoc[0] = Quad->Loc[0];
tLoc[1] = Quad->Loc[1];

Quad->Loc[0] -= 320.0f;
Quad->Loc[0] *= Quad->zScale;
Quad->Loc[0] += 320.0f;

Quad->Loc[1] -= 240.0f;
Quad->Loc[1] *= Quad->zScale;
Quad->Loc[1] += 240.0f;

// Transform it...
// ---------------

TransformQuad(Quad);

Quad->Loc[0] = tLoc[0];
Quad->Loc[1] = tLoc[1];


Pretty contrived, and it's not very precise, and it doesn't have the same level of control as remigius's idea, but it looks good. The zScale value is increased exponentially, which makes the object scale rapidly when it's close to the camera but scale very slowly when it's very far away. 'frameTime' is the time between the last gameloop iteration and this one, and the 4.0f that frameTime is divided into is just something to slow things down a bit (puts the brakes on your ship!). The function TransformQuad() transforms a quad into a virtual 640x480 gamescreen, which is why the quad's location is manipulated by the numbers 320 and 240 (moves the quad to the middle of the screen).

So in a nutshell, the zScale is increased exponentially, then the quad is moved to the middle of the screen, then the zScale modifier is performed to the quad's x/y position, and finally the quad is transformed to its gamescreen location. The final effect is an object that slowly scales and moves in from a very far away location, and scales and moves faster as the object gets 'closer' (as the zScale value gets bigger).

Purdy sweet! Now that I have my effect working, it's back to work getting the game put together. Wish me luck, and thanks again for the help! [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this