Question

I am implementing a game with a camera view like in Diablo 3 (3d objects on a 3d surface, top-down view), but I have one limitation:

I need my game to disregard distance in any respect.

That includes having all the 3d models face the camera from the same angle in ANY place on the screen, having the same size in any place on the screen and moving with the same speed (screenspace-wise).

I need this due to the specific mechanics I have in mind and I need it to be in a 3d world, because I what to have accurate shadows in the game.

I know how to implement every feature (mainly by using orthogonal projection and some shader magic) but the last one, that is I can't understand how to move a 3d object, positioned on a 3d plane with the very same speed screenspace-wise.

If the object is in the upper part of the screen, it will move slower, and vise versa, so I do need some code to compensate for that.

Do you guys have any idea how this can be done?

P.S. Thanks for editing btw, it does look better.

Edit: I am coding in c#/XNA

Was it helpful?

Solution

Not very neat math, but I hope it works for you:

Input

Suppose you are given a

  • worldViewPerspectiveMatrix M (Transforms world space to perspective space, orthogonal matrices should work as well!)
  • a constant velocity (more specifcally a distance per Frame) in screen space v_screen
  • a (normalized) direction vector V_dir in world space, this will give the direction your object moves. The actual length of the vector will be calculated.
  • a position X where your Object is placed in world space.

Result

  • a scaling factor a for moving your object 'v_screen' units in screen space along V_dir in world space. Thus you want to move your object actually X += a*V_dir.

First we use the formula of mapping the world space to screen space by using homogenous coordinates and w-clipping. The . denotes the matrix multiplication operator.

X_proj := M.(x,y,z,1);
X_screen := (x_proj/w_proj,y_proj/w_proj);

From there we can specify the position of the object X in screen space and the position after appling the directional movement X+(a*V_dir).

The length in screenspace and therefore the desired distance (per frame) is simply

Length[(X+(a*dir))_screen - X_screen] == v_screen.

Let's solve this for a. I used my Mathematica to calculate a for you. If you want further details, I may elabourate the answer. Suppose M, X, and V_dir is

         / xp \          / vx \                        / vxp \
X_proj = | yp |  V_dir = | vy |    V_proj = M.V_dir =  | vyp |
         | zp |          | vz |                        | vzp |
         \ wp /          \ 0  /                        \ vwp /

And v_screen is your desired screen space velocity. Then a is:

vlen = v_screen*v_screen;
a = (-dwp*vlen*wp + dxp*xp + dyp*yp + 
    0.5*Sqrt(
       Power(-2*dwp*vlen*wp + 2*dxp*xp + 2*dyp*yp,2)  - 
       4*(dxp*dxp + dyp*dyp - dwp*dwp*vlen)*(xp*xp + yp*yp - wp*wp*vlen)
       )
    ) /
    (dxp*dxp + dyp*dyp - dwp*dwp*vlen);

Remember, -a is also a solution.

OTHER TIPS

Guess what, due to the specifics of the orthogonal view, simply specifying the orthogonal matrix as Projection solved all problems by itself. The models move with the same speed and keep the size nomatter where they are positioned. However, the only problem is the fact that when you change screen resolution the world does not adapt to it. So we have to use scale factors that rely on the current screen resolution to scale our world manually when the game is loaded.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top