I am writing 3D graphics software in Java using the LibGDX framework (which is a front-end for OpenGL), and am baffled by a transformation problem. How do I rotate the orientation of the camera or models being displayed by the dx and dy inputs from a mouse?
Click here to view the full source code of a concise demo in github.com
But, here is the method where I'm certain the problem and solution will be found:
@Override public boolean touchDragged( int screenX, int screenY, int pointer )
{
lastX = screenX-lastX;
lastY = screenY-lastY;
// distance of mouse movement
screenAng = (float) Math.sqrt( lastX*lastX + lastY*lastY );
// direction vector of the AOR
screenAOR.set( lastY/screenAng, lastX/screenAng, 0f );
if ( touchedButton == 0 )
{
cubes[ selectedCube ].modelInstance.transform.rotate( screenAOR, screenAng );
}
else
{
camera.rotateAround( Vector3.Zero, screenAOR, -screenAng/5.5f );
camera.update();
}
lastX = screenX;
lastY = screenY;
Gdx.graphics.requestRendering();
return true;
}
EDIT: Thanks to Andrew Wilson for his comment below. I edited the camera section and it works properly now. Still working on the model section...
{
// transform the screen AOR to a world AOR
// get the camera transformation matrix
tempMat = new Matrix4( camera.view );
tempMat.translate( camera.position );
tempMat.inv();
// transform the screen AOR to a world AOR
worldAOR = transformThings( tempMat, screenAOR, new Vector3() ).nor();
// apply the rotation of the angle about the world AOR to the camera
camera.rotateAround( Vector3.Zero, worldAOR, screenAng/5.5f );
camera.update();
}
EDIT: I edited the model section and it still is giving me some grief - it looks like it's orbiting the world origin instead of rotating around the model origin. Here's what it looks like so far:
{
// transform the screen AOR to a model AOR
// get inverse of the camera transformation matrix
tempMat.set( camera.view );
tempMat.translate( camera.position );
tempMat.inv();
// get inverse of the model transformation matrix
Vector3 tempPos = cubes[ selectedCube ].position;
cubes[ selectedCube ].modelInstance.transform.translate( tempPos.cpy().scl( -1 ) );
tempMat2.set( cubes[ selectedCube ].modelInstance.transform );
tempMat2.inv();
// multiply the camera and model matrices together
tempMat.mul( tempMat2 );
// transform the screen AOR to a model AOR
modelAOR = transformThings( tempMat, screenAOR, modelAOR ).nor();
// apply the rotation of the angle about the model AOR to the model
cubes[ selectedCube ].modelInstance.transform.rotate( modelAOR, -screenAng );
cubes[ selectedCube ].modelInstance.transform.translate( tempPos );
}
Here is an image that the demonstrates the problem:
I want the object to rotate in the direction it is dragged by the mouse, no matter which direction it happens to be orientated at the time. As it is now, when I first drag the mouse to the right, the object rotates to the right about the screen Y axis as expected; but then when I drag the mouse upward I want the object to rotate upward about the screen X axis, but instead it spins to the left about the screen Z axis. Think of it like a floating ball in a bowl of water - whichever way you swipe at it, it ought to rotate in that direction.
It seems to me that the mouse movement is transforming the objects directly in their local coordinate system; but instead I think I need to transform the axis of rotation itself from the Screen Coordinate System into the Object Coordinate System before applying it to the object. I just can't figure out how to do it.
I would really appreciate any insight or help to resolve this; I'm running out of hair to pull out... Thanks in advance.