How do I map a 2D set of points to 3D-perspective correction

0 favourites
From the Asset Store
Create your own adventure map with this easy to use asset pack.
  • I have mapped the red ball of the bottom top-view 2D table onto the top pseudo-3D table using essentially linear interpolation of the points. The red ball's X position on the 3D table is accurate. The *y* coordinate however is very wrong. See the ball on the 3D table isn't nowhere near the pharaoh's feet.

    From what I gather, I need to take Z into account somehow, but I don't know how.

    If anyone ( R0J0hound ?) has any ideas? I don't need texture mapping, just coordinate mapping.

    Thank you

    Here is my .capx ... pping.capx

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • it's hard to describe this in text, but you need to define you angle of perspective... then by trigonometry you'll be able to map your points.

    the x co-ordinate in your example is fine as it does not change no matter what you do, but as you said y/z are a different. it is called 3D projections so feel free to google that term.

    so think of it this way ... look at a wire-frame box.. as you move your perspective from looking in at the box on one face and up and over.. x doesn't change, but you'll see some combination of the original face and now another face.. that gives you a bigger space.. and how it contributes to a final co-ordinate depends on the degree of rotation you've done.

    if I may suggest Wikipedia... it has a good description, just remember you're keeping one axis constant, so it becomes a lot simpler than what is described here/

    perspective (where far away things look smaller than near things) is again a case of trig, but too complex to describe here

  • rho thank you for the rapid response!

    Unfortunately I haven't been able to understand vector math too well, and the wikipedia article is way above my league. I just intuitively know I should factor in Z somewhere in my calculations of the Y' coordinate of the ball on the 3D table.

    Maybe I'm not smart enough for this

  • x = centerX + cos(angle) * distance

    y = centerY + sin(angle) * distance

    z = centerZ + sin(angle) * distance

    Just think of z as another y, another plane, that works just like the y, except it intersects x, and y, ...oh and scales in size as it gets larger, and closer to the center.

  • This may work:

    In it's basic form a perspective projection in just dividing x and y by z.

    This is the 2d map.
    o1 is the top-left corner and p is a point to project.
    |     |
    | p   |h
    |     |
    Convert them to u and v to get coordinates from 0-1
    Next we have the perspective sprite.  w1 and w2 are the widths of the top and bottom. o2 is the top-left and h2 is the height.
    o2  ______     -+
       /      \     |
      /        \    | h2
     /          \   |
    /____________\ -+
    We find the z from v with:
    z = w2/lerp(w1, w2, v)
    Then we can do the perspective transform with:
    screenx = ((u-0.5)/z + 0.5)*w2 + o2.x
    screeny = ((v-0.5)/z + 0.5)*h2 + o2.y
  • Thank you everyone. newt this seems to be over my head too :/

    R0J0hound always a step ahead.

    This actually produces very weird results: ... ping2.capx

    There is some 3D projection going on, (drag and drop the ball to see), but it's not right at all.

    So your calculation of Z gives

    Z= w2/w1 when V=0 and Z= w2/w2 when V=1

    So Z is from 1 (nearest) to about 1.7 in this case. Why? What does this number represent?

    Follow up questions:

    1.Why do you calculate Z like that?

    2. Why are we dividing (u-0.5) /z ?

    Thank you for taking the time everyone. Please let me know if I can pixel something for you in return <3

  • I didn't test it so there may be errors. Also I can't look at the capx till tomorrow.

    Z is the distance from the eye, which is at z=0. The camera is at z=1. Anything further will have a greater z which in turn will look smaller since the perspective is calculated with x/z, y/z. Basically the bottom width divided by 1.7 should equal the top width.

    1. The idea I had was to find how far away the back edge would have to be if it was that width. Without perspective the top edge should be just as wide as the bottom. With perspective the same projection formula can be used proj_width=width/z. Sovlving for z it come out to z=proj_width/width, and then it's just a matter of interpolating by y or v.

    2. The 0.5 is so we're scaling at the center instead of the left edge. U and v are in the range of 0 to 1, so 0.5 is halfway. Also /z is scaling.

    As a simple example say you wanted to double the x distance from 320 you'd do:

    X=(x-320)*2+320 if instead we wanted to just scale from 0 it would be


  • christina

    Here is a capx with the idea I posted. The only error was "screeny = ((v-0.5)/z + 0.5)*h2 + o2.y" needed to be changed into "screeny = (v/z)*h2 + o2.y". ... sform.capx

    I tested it with a plane rendered with two different field of views and it seems to become less accurate if I use a fov other than 60. It probably needs to account for that somehow.

    Your last capx isn't working right because it's it's scaling from the left instead of the center. See 2 above^

    Also for your original capx changing the set y expression to "board.Y + (relativeY*board.Height) /lerp(2,1,relativeY)" seems to get the y working better. You can adjust 2 to change the strength of the effect.

  • R0J0hound I just logged in to tell you you're absolutely right about the Y axis, that's totally the way to go! And I fixed the X axis calculation like you did.

    And thank you *so* much for taking the time to make a capx <3

    I owe you lots, and we all do.

  • R0J0hound Just a quick untested thought, maybe we can get the FOV into account by using a "scaling" var, like this:

    scaling = (x_resolution/2) / tan(fov_angle/2).

    Then we use

    y = (y_world * scaling) / z

  • I think we need a more precise approach. So instead we could use this equation:

    screenx = x /(z/d - cz)[/code:3lrqao82]
    cz is the z of the camera
    and d is the distance from the screen which is the same as tan(fov_angle/2).
    Then instead of finding the z of the back edge we'll assume it's 2 and solve for cz and d.
    The math worked out to be:
    screenx = x/((z-1)*(BottomWidth/TopWidth)+1)
    Actually I had a -1 in there so some reason which was throwing it off until I removed it.
    I updated my example in my first post.  Click to switch between the old method and the new.  The new matches the grid much better when the fov is different.
  • R0J0hound you can't resist a math challenge can you?


    Thanks for all the help, it's the first time I understand *all* of your math.

    You're incredible.

    Oh and here's a wip of the game you've helped

  • Looks fun.

  • R0J0hound , R0j0 assuming the z of the back edge is "2" seems to have a strange effect: these pairs of rectangles now only work if they are the same relative size.

    If I resize the perspective rectangle without resizing the top-down rectangle, the equations don't work at all.

    If the top-down rect is 400x400, the perspective rect has to be 970x330. I don't know what this ratio means. Do you?

    I don't mind working with this limitation, I just thought I'd make a note of it. Thanks again <3

  • R0J0hound

    Um. I've lost track of the math again, but your prototype only worked for a specific ratio.

    I tried to change that ratio to something more useful. So, if the world width and the perspective rectangle bottom width are equal, the ratio comes out as 2.425

    Did you use actual pixel dimensions when you made the assumption that Z=2 ?? Is that where this number comes from?

    Anyhow, it works well for now and until I can go back and re-check your genius math. <3 ... ction.capx

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)