Thread: Converting from Screen to World Coordinates

  1. #1
    l'Anziano DavidP's Avatar
    Join Date
    Aug 2001
    Location
    Plano, Texas, United States
    Posts
    2,743

    Converting from Screen to World Coordinates

    Eh...this seems to be a fun thing every programmer goes through...converting screen to world coordinates. It's always been a hastle trying to get it to work in my previous game projects. Sometimes I managed to get a hacked up version of it working, but this time I wanted to consult the cboard and see if I could gain any wisdom in the process.

    It seems my game projects have finally gone full circle. I started out making an RTS using DirectX 3 years ago, then I scrapped it to work on a 2d side scrolling game, then I scrapped that to work on a 3d mech game, and then I scrapped that to work once again on an RTS. I have, however, learned much over the past 3 years and feel I can do much more with the RTS environment than I was able to do 3 years ago.

    3 years ago I created a hacked up way of converting from screen to world coordinates, but it was messy, and sometimes got wrong answers, so I decided to come here before plunging into it.

    I am using hotspots, per say. For example, if I have a tree, I have a hot spot for that tree sitting at the bottom of its trunk. That hot spot will be used in all calculations for finding the world coordinate of that tree.

    I am also using an isometric tile system. In essence, tiles look like diamonds when sitting alone and not with any other tiles. Therefore, if it is any help in the end, essentially they can be cut into 4 right triangles.

    So I need a fast, efficient, low-cost way to convert from screen coordinates to world coordinates. Let's say I have a swordsman walking across the map, for example. His world coordinate will need constant updating according to where he is on the screen.

    The very first option that comes to mind is this:

    Knowing the width of a tile, use division to calculate how many tiles over from the left of the screen the character is.
    Use the same method to calculate how many tiles down the character is. The resulting two numbers is the world coordinate.

    At first glance this would work, and this is the method I used 3 years ago in my very early RTS game, however, when looked deeper into, it would not work at all.

    Reason is because if the map is any larger than the screen, once you move over far enough on the map you would lose the correct world coordinate. For example, if you move far enough to the right, the screen would end up scrolling right, and then you would lose the calculation.

    One way around this is the blit the whole map to a temporary surface, and then using an SDL_Rect (I am using SDL) I could blit the appropriate part of the map on to the screen, yet I wouldn't lose the coordinates I need because the current x and y offsets would be stored in the rect. I could use those offsets to help in the world coordinate calculation.

    Still, this method seems clunky and slow. That would be performing division operations every frame of animation...for every unit.

    I could of course optimize it to only perform those operations once at the very beginning of the game for those units that do not move (trees, rocks, gold mines, etc.), and that would speed it up quite a lot.

    But anyways, anyone have any enlightening information on converting screen coordinates to world coordinates?

    [edit]
    I have also thought about the possibility of basing everything in world coordinates instead of screen coordinates.

    Then I would do world to screen conversions instead of screen to world conversions.

    I dont think this would work, however. That would make it seem much more turn based and not real time, because moving from one world coordinate to another is a much bigger jump than moving from one screen coordinate to another.
    [/edit]
    Last edited by DavidP; 05-09-2004 at 10:59 PM.
    My Website

    "Circular logic is good because it is."

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    If you are simply talking about 2D here then you are pretty much doing the right thing already.

    1. Compute which cell the object in question is in
    2. Compute world coords for that cell - multiply by cellsize
    3. Compute how far into the cell object is
    4. Compute world coords for object
    5. Add difference of cell world coords and object world coords to object world coords


    The flaw in your algo is that it does not take into account the current scroll positions of your map. You want how far into the map your object is...not how far into the screen. All you need to do is add the scroll amounts to what you already have and it will work for all camera positions.

    But if camera scrolling is implemented in world coordinates then you must add (scrollx/cellsize) and (scrolly/cellsize) to playercellx and playercelly.

  3. #3
    Shadow12345
    Guest
    You use OpenGL, look into glUnProject (or maybe it's gluUnProject, I can't remember, and I've never used it). I see people all the time asking to use this for picking 3d objects in a scene.

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I was under the impression that a 3D transform cannot be undone.

  5. #5
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    well, it can and it can't. I think it's the equivalent of shooting a ray from the viewpoint, through the near clipping plane where the mouse cursor resides, and finding the closest 3D object that lays on this ray

  6. #6
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Quote Originally Posted by Bubba
    I was under the impression that a 3D transform cannot be undone.
    A 3D transform can be easily undone if it is an invertible matrix. Simply apply the inverse and it will undue the transformation.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  7. #7
    Shadow12345
    Guest
    well, bubba knows that, but he was talking about a scenario where you know nothing other than a point on the screen.

  8. #8
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Quote Originally Posted by Shadow12345
    well, bubba knows that, but he was talking about a scenario where you know nothing other than a point on the screen.
    Okay, it wasn't quite clear to me I guess. If you just know the point then no there is no way. You have to know the matrix transforms that were used to get that final position.

    *World
    *View
    *Projection
    *Viewport

    All of those transforms must be known to get the position back to object space.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  9. #9
    Shadow12345
    Guest
    which is probably what the unproject function I mentioned does.

    However, you can do the calculations in worldspace by calculating where the point on the screen is in 3d space is, subtract from that the position, and you get a ray. shoot that ray out into the world and see what it hits in worldspace.

  10. #10
    l'Anziano DavidP's Avatar
    Join Date
    Aug 2001
    Location
    Plano, Texas, United States
    Posts
    2,743
    okay sorry i havent replied to this thread at all. ive been working a lot on other stuff...making great progress actually, and now I have come back to this problem to handle it now.

    I have attached two images at the bottom to show what my tile set is like. Keep in mind that this is a 2d RTS I am working on, not a 3d OpenGL program. So the tile set is isometric.

    The first attachment is simply a picture of the top left hand corner of a map that is composed of all grass tiles.

    The second attachment is my current tileset (which will be expanded upon as development continues).

    The third attachment will be explained after the next paragraph.

    Now, When I made a matrix of tiles so every tile is refered to by its world coordinate as tileMatrix[xCoord][yCoord]. I also created a set of equations to convert that world coordinate into a screen coordinate so I would know where to blit that tile on the screen. I had to work with these equations to get them aligned correctly and working properly. The resultant equations are:

    ScreenX = (MatrixX * TERRAIN_WIDTH) / 2 - MatrixX

    and

    ScreenY = (MatrixY * TERRAIN_HEIGHT) + ((x % 2 == 0)? 0 : (TERRAIN_HEIGHT / 2) ) - MatrixY


    In shorthand, those would be:

    Px = (1/2)xw - x

    and

    Py = yh + ((x%2==0)? 0 : h/2) - y

    Now, knowing all this, the third attachment shows the format of how things are stored in my matrix. All the tiles with magenta dots would have the coordinate tileMatrix[xCoord][0], and all the ones with blue dots would have the coordinate tileMatrix[xCoord][1].

    So now I have a fighter moving across the map and I know its screen coordinate but not its world coordinate.

    The ideal way to calculate its world coordinate would be to manipulate the equations I have above using algebraic laws and isolate and solve for MatrixX and MatrixY, instead of solving for ScreenX and ScreenY.

    So let's go ahead and try and do that using Equation 1 for the x coordinate:

    p = (1/2)xw - x
    p + x = (1/2)xw
    x = (1/2)xw - p

    And when you divide out x:

    x/x = (1/2)w - p/x
    1 = (1/2)w - p/x
    1 + p/x = (1/2)w
    p/x = (1/2)w - 1
    p / ((1/2)w - 1) = x
    x = p / ((1/2)w - 1)

    Is my algebra correct?

    Equation 2 turns into:

    p = yh + ((x % 2 == 0)? 0 : h/2 ) - y
    y = yh + ((x % 2 == 0)? 0 : h/2 ) - p

    And when you divide out y:

    y/y = h + (0 or h/2)/y - p/y
    1 = h + (0 or h/2)/y - p/y
    1 = h + ((0 or h/2) - p)/y
    1 - ((0 or h/2) - p)/y = h
    - ((0 or h/2) - p)/y = h - 1
    - ((0 or h/2) - p)/y = h - 1
    - ((0 or h/2) - p) / (h - 1) = y
    y = ((0 or h/2) - p) / (h - 1)

    Is my algebra correct?
    My Website

    "Circular logic is good because it is."

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Get coordinates on screen when user clicks?
    By Jake.c in forum Windows Programming
    Replies: 10
    Last Post: 01-18-2009, 10:54 PM
  2. console screen (Windows)
    By hakan in forum C++ Programming
    Replies: 1
    Last Post: 03-12-2008, 06:35 AM
  3. Render text
    By Livijn in forum C++ Programming
    Replies: 6
    Last Post: 07-06-2007, 03:32 PM
  4. char copy
    By variable in forum C Programming
    Replies: 8
    Last Post: 02-06-2005, 10:18 PM
  5. OpenGL coordinates
    By Da-Nuka in forum Game Programming
    Replies: 5
    Last Post: 01-10-2005, 11:26 AM