Sign in to follow this  
HyperHacker

OpenGL 3D cursor movement

Recommended Posts

I'm writing a map editor for a simple, old, closed-source 3D game. This game engine has no concept of objects - the maps are only a lot of display lists, textures, and vertices, with collision meshes generated from the display lists at runtime. While my program is capable of grouping vertices and manipulating them as a whole, it ultimately needs to know the world coordinates of each vertex to export for this engine. I'm using a Wii remote to move the cursor, which is a floating cube. Whenever a vertex is inside the cube it can be dragged around or selected. Dragging also moves all selected vertices; additionally, the D-pad can be used to move them one unit at a time. I also hope to implement rotating all selected vertices around the camera's Z axis. Currently the camera is not able to rotate on the Z axis, because last time I tried to do that it nearly drove me batty. I'd love to get that working though. The actual Wiimote and cursor logic is done in Lua, using LuaGL. (The interface itself, if it matters, is GTK+ with GtkGlExt.) A function in the script is called periodically with a pointer to the window, which contains the cursor (and potentially multiple cursors in the future). It reads the Wiimote's IR/motion sensors to see where it's pointing (which gives you a rough distance-from-screen as well) and uses that to update the cursor position. Originally, I was using this code to do the transformations necessary for moving the camera, cursor, and selected vertices. It worked fine for the first two, but if I pointed my camera straight down the Y axis and moved some vertices they'd all just fly off in various directions.
-- Transforms coordinates relative to a point to world coordinates.
-- Inputs:
-- -FromX, FromY, FromZ: Point which coordinates are relative to.
-- -FromRotX, FromRotY: Rotation of this point.
-- -MoveX, MoveY, MoveZ: Distance from point.
-- Returns: X, Y and Z world coords.
-- Notes:
-- If distance is not important you can use 0,0,0 for FromX,FromY,FromZ. This
-- allows you to move something relative to its current position while
-- accounting for camera rotation, e.g:
-- DX, DY, DZ = MoveFromPoint(0, 0, 0, RotX, RotY, DX, DY, DZ)
function MoveFromPoint(FromX, FromY, FromZ, FromRotX, FromRotY, MoveX, MoveY, MoveZ)
   --Reset matrices
   gl.MatrixMode(gl.PROJECTION)
   gl.PushMatrix()
   gl.LoadIdentity()

   gl.MatrixMode(gl.MODELVIEW)
   gl.PushMatrix()
   gl.LoadIdentity()

   --Rotate
   gl.Rotate(FromRotX, 1.0, 0.0, 0.0)
   gl.Rotate(FromRotY, 0.0, 1.0, 0.0)

   --Get resulting modelview
   Matrix = gl.GetArray(gl.MODELVIEW_MATRIX)
   
   --Restore matrices
   gl.PopMatrix()
   gl.MatrixMode(gl.PROJECTION)
   gl.PopMatrix()
   gl.MatrixMode(gl.MODELVIEW)
   
   --[[How the 1-based 1-dimensional indices of Matrix map to a 4x4 matrix:
     0__1__2__3
   0|1  2  3  4
   1|5  6  7  8
   2|9  10 11 12
   3|13 14 15 16 ]]
   
   --Move
   local X, Y, Z
   X = -FromX + (MoveX * Matrix[1]) + (MoveY * Matrix[2]) + (MoveZ * Matrix[3])
   Y = -FromY + (MoveX * Matrix[5]) + (MoveY * Matrix[6]) + (MoveZ * Matrix[7])
   Z = -FromZ + (MoveX * Matrix[9]) + (MoveY * Matrix[10]) + (MoveZ * Matrix[11])
   return X, Y, Z
end

Someone else suggested this, which looks right to me:
function MoveFromPoint(FromX, FromY, FromZ, FromRotX, FromRotY, MoveX, MoveY, MoveZ)
   --Assume we're in MODELVIEW matrix mode
   gl.PushMatrix()
   gl.LoadIdentity()

    -- Starting point
   gl.Translate(FromX, FromY, FromZ)

   -- Apply rotate
   gl.Rotate(FromRotX, 1.0, 0.0, 0.0)
   gl.Rotate(FromRotY, 0.0, 1.0, 0.0)

    -- Apply move
    gl.Translate(MoveX, MoveY, MoveZ)

   --Get resulting modelview
   Matrix = gl.GetArray(gl.MODELVIEW_MATRIX)
   
   --Restore matrix
   gl.PopMatrix()
      
    -- The translated point is in the last row of the matrix
    return Matrix[12], Matrix[13], Matrix[14]
end
However, this isn't working properly either - the cursor is not moving with the camera at all; always moving relative to the origin with no rotation. I know very little about 3D/matrix math but it certainly looks like it should work; I can see it translate to the starting point (in this case, the camera position), rotate, and then move the specified distance, which in my mental visualization should do the job exactly. It seems only the last gl.Translate() is actually having any effect. I have verified that the inputs are correct.

Share this post


Link to post
Share on other sites
Well I figured out why the cursor wasn't moving with the camera. It actually was moving in the opposite direction (e.g. if the camera is at (0, 0, -5) the cursor would be at (0, 0, 5)), and the perspective made it look like it hadn't moved at all.

However, moving vertices with the D-pad still doesn't work. It works fine if the camera is not rotated. If I look straight down the Y axis at them and move them, they still fly off in random directions. So, the replacement MoveFromPoint() didn't really fix anything, just caused a lot of headache.

[edit] It happens with Y axis rotation as well, which is easier to see. Video demonstration.

[edit 2] HA. It's a damn Lua bug.

Fails:
DX, DY, DZ = MoveFromPoint(0, 0, 0, -RX, -RY, DX, DY, DZ)
X, Y, Z = X + DX, Y + DY, Z + DZ
Vertex_SetPos(v, X, Y, Z)
Works:
local RDX, RDY, RDZ
RDX, RDY, RDZ = MoveFromPoint(0, 0, 0, -RX, -RY, DX, DY, DZ)
X, Y, Z = X + RDX, Y + RDY, Z + RDZ
Vertex_SetPos(v, X, Y, Z)
Apparently passing a variable as a parameter and also assigning a return value to it doesn't work so well. My zeros were randomly becoming ones or 0.126somethings on return. Figures. -_- It's nearly working now.

I also found I needed to use the inverse of the camera rotation (i.e. -RX, -RY), else my controls would get all messed up.

However, there's still a control issue when rotating on multiple axes. It works well if rotated on a single axis, or not at all:
Up: Move away from camera
Down: Move toward camera
Left: Move left
Right: Move right

However, when rotated 90 degrees on both X and Y, there's a bit of a consistency problem:
Up: Move up (toward top of screen)
Down: Move down (toward bottom of screen)
Left: Move away from camera
Right: Move toward camera

It's even worse at 45 degrees:
Up: Move toward upper right corner of screen
Down: Move toward lower left corner of screen
Left: Same as up
Right: Same as down

O.o

[Edited by - HyperHacker on July 25, 2009 11:16:43 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this