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
Not very neat math, but I hope it works for you:
Suppose you are given a
M
(Transforms world space to perspective space, orthogonal matrices should work as well!)v_screen
V_dir
in world space, this will give the direction your object moves. The actual length of the vector will be calculated.X
where your Object is placed in world space.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.