Converting Coordinates
Monkey Forums/Monkey Programming/Converting Coordinates
| ||
If anyone is kick-ass at matrix stuff, I have a World-Space and a Camera-Space. The Camera can scroll/rotate/zoom, the World is always the same, however from the viewers angle it looks like the world turns/rotates/sacles. If that makes sense, here is my problem. Atm to get what I call is ScreenCoordinates I use Warpy's tip: Local matrix#[] = GetMatrix() Local screenX:Float = matrix[0] + matrix[2] + matrix[4] Local screenY:Float = matrix[1] + matrix[3] + matrix[5] This is after that object has been rotated and translates and so on, it can in after a long series of pop-push matrices. This works great, but now I instead want the world-coordniate the object has. So I figured I'd simply do a GetMatrix() into a Global called WorldMatrix after the Camera Translation/Rotate/Scale, and then go: Local matrix#[] = WorldMatrix Local worldX:Float = matrix[0] + matrix[2] + matrix[4] Local worldY:Float = matrix[1] + matrix[3] + matrix[5] But this does not seem to work. Is the logic correct? Am I missing something obvious or should I just keep working on it? |
| ||
Please look at bananas/warpy/transform/transform_mouse.monkey It does exactly what you want. Use Transform([pointarray]) instead of that GetMatrix three-liner you've got there. |
| ||
Warpy, thanks! I'm still having some trouble. Transform WorldMatrix Local coords#[] = InvTransform([node.Position.X, node.Position.Y]) node.WorldPosition.Set( coords[0], coords[1] ) Local matrix#[] = GetMatrix() node.ScreenPosition.Set matrix[0] + matrix[2] + matrix[4], matrix[1] + matrix[3] + matrix[5] This is how it looks now. The ScreenPosition is perfectly calculated for all nodes. WorldPosition is not right though. With world position I mean the position that is independant of zoom, rotation or translation of the camera. In other words if I measure the distance between two points in the world I expect the distance to be constant during camera zoom/rotate, but only change if the object's themselves move. Also I assumed that the correct place to set the WorldMatrix is before the camera update/translation, and I set it using GetMatrix, is that assumption correct? |
| ||
Why are you using transformation matrices to move things in world co-ordinates? How is node.Position different from node.WorldPosition or node.ScreenPosition? So, a few things: 1. Transform applied to a float array interprets the array as pairs of 2d co-ordinates and applies the current transformation matrix to them. The version of Transform which takes six float arguments applies the given transformation matrix to the current transformation matrix, which is also not what you want. You want SetMatrix WorldMatrix 2. You've got the formula for applying a transformation matrix to a point wrong - the version you have returns the same numbers for any input co-ordinates, because it doesn't use them! The formula should be newx = matrix[0]*oldx + matrix[1]*oldy + matrix[4] newy = matrix[2]*oldx + matrix[3]*oldy + matrix[5] |
| ||
Hi, Was away last week, sorry for replying so late, awesome help so far :) I'm getting results in the right direction, now everything works except that the worldPosition I get is only relative to the first layer, unlike screenPosition which is absolute (not related to how many push/pop has been done) This is how the logic looks like: Method Render:Void() If AttachedList For Local node:GraphicsNode = Eachin AttachedList PushMatrix() graphics.Rotate RotationAngle graphics.Scale Size, Size graphics.Translate node.Position.X, node.Position.Y Local matrix#[] = GetMatrix() node.ScreenPosition.Set matrix[0] + matrix[2] + matrix[4], matrix[1] + matrix[3] + matrix[5] SetMatrix WorldMatrix Local worldMatrix#[] = GetMatrix() Local newx:Float = worldMatrix[0]*node.Position.X + worldMatrix[1]*node.Position.Y + worldMatrix[4] Local newy:Float = worldMatrix[2]*node.Position.X + worldMatrix[3]*node.Position.Y + worldMatrix[5] node.WorldPosition.Set( newx, newy ) SetMatrix matrix node.Render() PopMatrix() Next End node.Position is the Object's local coordinates. If the object is attached Directly to the world then this is Equal to WorldPosition. ScreenPosition is the actual coordinate, as seen on screen, and when zooming with the camera the ScreenPosition changes, but WorldPosition or Position does not. WorldPosition is meant to be the object location in the world, but I'd prefer to not have to loop all parent objects to figure out the translation of this object, ScreenPosition is calculated is such a beutiful way, I figured I could do the same for WorldPosition? Insteaf of multiplying with Position I'd like to multiply with WorldPosition, but this creates a paradox in that the world layer must use Position, since before WorldPosition is calcualted it is 0. |
| ||
Or maybe I can use the Screen-Coordinates and Inverse/undo the Camera's matrix? I just realized, I'm solving an impossible problem. The only reason the Screen-Coordinates appear correct is that I'm using a camera that has the exact same position and size as the screen. Obviously, if I had 2 cameras, an object's screen position would be different on each of these cameras. However the world position is the same. I'm thinking of a method like this: Method ScreenCoordinates:Vector( camera:Camera ) 'Use camera's matrix to calculate the position in screen-space End |
| ||
Yes, that's correct. Please have another look at my transform_mouse example. |
| ||
Cool, going forwards, but I think I'm a bit stuck again! XD I have this now: Method Screen:Vector( camera:Camera ) Local screenMatrix#[] = camera.MatrixAfter Local newx:Float = screenMatrix[0]*Position.X + screenMatrix[2]*Position.Y + screenMatrix[4] Local newy:Float = screenMatrix[1]*Position.X + screenMatrix[3]*Position.Y + screenMatrix[5] ScreenPosition.Set newx,newy Return ScreenPosition End Method Map:Vector( camera:Camera ) Local worldMatrix#[] = camera.Matrix Local newx:Float = worldMatrix[0]*Position.X + worldMatrix[2]*Position.Y + worldMatrix[4] Local newy:Float = worldMatrix[1]*Position.X + worldMatrix[3]*Position.Y + worldMatrix[5] WorldPosition.Set newx,newy Return WorldPosition End It works but it does not take into account what the object is attached to. I'm doing something wrong I guess. I'm quite comfortable with Matrices in math and doing projections, but I have little experience on how to use Matrices in practice in game programming, like in this situation. EDIT, Update: I managed to get Screen Coordinates to work using the Parent Matrix, which I by no logic call MyMatrix. 'Working! Method Screen:Vector( camera:Camera ) Local parentMatrix#[] = MyMatrix Local tmx:Float = parentMatrix[0]*Position.X + parentMatrix[2]*Position.Y + parentMatrix[4] Local tmy:Float = parentMatrix[1]*Position.X + parentMatrix[3]*Position.Y + parentMatrix[5] Local screenMatrix#[] = camera.Matrix Local newx:Float = screenMatrix[0]*tmx + screenMatrix[2]*tmy + screenMatrix[4] Local newy:Float = screenMatrix[1]*tmx + screenMatrix[3]*tmy + screenMatrix[5] ScreenPosition.Set newx,newy Return ScreenPosition End 'Not Working on attached objects, so almost working... Method Map:Vector( camera:Camera ) Local parentMatrix#[] = MyMatrix Local tmx:Float = Position.X Local tmy:Float = Position.Y Local worldMatrix#[] = camera.Matrix Local newx:Float = worldMatrix[0]*tmx + worldMatrix[2]*tmy + worldMatrix[4] Local newy:Float = worldMatrix[1]*tmx + worldMatrix[3]*tmy + worldMatrix[5] WorldPosition.Set newx,newy Return WorldPosition End Map, is what I before called World. The world coordinates are calculated correctly, however when I move an Object, that has objects attached to it, the attached objects are un-affected, but of course I expect them to move. I feel I'm not doing a good job explaining my predicament here, but maybe I get across a bit :P Warpy, any ideas what I'm missing here? :) |
| ||
SOLVED!! So if anyone has any interest, here is the solution I found that did work. Please comment if there is a better or more optimized way of doing it. ' Working! Method Screen:Vector( camera:Camera ) Local parentMatrix#[] = MyMatrix Local tmx:Float = parentMatrix[0]*Position.X + parentMatrix[2]*Position.Y + parentMatrix[4] Local tmy:Float = parentMatrix[1]*Position.X + parentMatrix[3]*Position.Y + parentMatrix[5] Local screenMatrix#[] = camera.Matrix Local newx:Float = screenMatrix[0]*tmx + screenMatrix[2]*tmy + screenMatrix[4] Local newy:Float = screenMatrix[1]*tmx + screenMatrix[3]*tmy + screenMatrix[5] ScreenPosition.Set newx,newy Return ScreenPosition End ' Working! Method World:Vector() Property WorldPosition.Set ParentPosition WorldPosition.Add Position Return WorldPosition EndIn the update Loop: PushMatrix() MyMatrix = GetMatrix() node.ParentPosition.Set( Position.X, Position.Y ) graphics.Rotate RotationAngle graphics.Scale Size, Size graphics.Translate node.Position.X, node.Position.Y node.Render() PopMatrix() So each frame I set the MyMatrix using GetMatrix() - I hope that's a quick operation. I also calculate this node's Parent's position by saving the Position of the parent, later on I use this (recursivly) to calculate the World Position. Many Thanks Warpy for your help in nudging me in the right direction, greatly appriciated! :D |