How to keep the rotation center stationary while moving objects with an arcball in Directx?

500 Views Asked by At

The Internet has some information about using arcballs with OpenGL, but not much for DirectX. I am using a version of the arcball function from the Microsoft DirectX SDK. It shifts the position of objects by altering its translation matrix by the change in mouse movement (fDeltaX and fDeltaY):

D3DXMatrixTranslation( &arcBall.mTranslationDelta, -fDeltaX, fDeltaY, 0.0f );
D3DXMatrixMultiply( &arcBall.mTranslation, &arcBall.mTranslation, &arcBall.mTranslationDelta );

The problem is that the rotation center is the same as the object center, so the rotation center moves with the objects. How can I keep the rotation center stationary?

To draw objects on the screen, I create a world matrix using the object's center location, and then I multiply it by the rotation matrix, and then by the translation matrix:

D3DXMatrixTranslation( (D3DXMATRIX*)&g_World_drawing, -g_vObjectCenterPtr.x, -g_vObjectCenterPtr.y,  -g_vObjectCenterPtr.z );
D3DXMatrixMultiply( (D3DXMATRIX*)&g_World_drawing, (D3DXMATRIX*)&g_World_drawing, ArcBall_GetRotationMatrix() );
D3DXMatrixMultiply( (D3DXMATRIX*)&g_World_drawing, (D3DXMATRIX*)&g_World_drawing, &arcBall.mTranslation );

Then I specify that world matrix for the drawing:

d3dDevice->SetTransform(D3DTS_WORLD, &g_World_drawing);

Do I need a separate rotation center, and if so, how do I use it? Or is there some way to compensate for moving the objects?

I created a very simple program in Visual Studio 2012 to show this problem. I added an arcball to the Rotating Cube tutorial at gametutorials.com, zipped up the folder, and posted it here along with a description of the problem and some screen images.

I can move the rotation center all by itself without the objects moving very much by setting up a translation matrix according to how much the mouse has moved, and then multiplying that by the rotation matrix, and then adding two of its values to the to the rotation center:

D3DXMatrixTranslation( &translationDelta, dPix->x * xfactor, dPix->y * yfactor, 0.0f );
D3DXMatrixMultiply( (D3DXMATRIX*)&translationDelta, (D3DXMATRIX*)&translationDelta, ArcBall_GetRotationMatrix(abPtr) );
g_vObjectCenterPtr->x += translationDelta._41;
g_vObjectCenterPtr->y -= translationDelta._42;

I then have to compensate for moving the rotation center by altering the arcball's translation matrix:

// now compensate for moving the object so that the object remains as motionless
D3DXMatrixTranslation( &translationDelta, translationDelta._41, -translationDelta._42, 0.0f );
D3DXMatrixMultiply( (D3DXMATRIX*)&translationDelta, (D3DXMATRIX*)&translationDelta, ArcBall_GetRotationMatrix(abPtr) );

D3DXMatrixTranslation( &arcBall.mTranslationDelta, translationDelta._41, translationDelta._42, 0);
D3DXMatrixMultiply( &arcBall.mTranslation, &arcBall.mTranslation, &arcBall.mTranslationDelta );

However, I've not been able to figure out how to combine the moving of the objects with a corresponding movement of the rotation center so that the objects move while the rotation center stays stationary. Does anybody know how to do this?

1

There are 1 best solutions below

1
On

I haven't tried your code or worked much directly in DirectX, but translating and then rotating will always rotate the point you translated to, whereas rotating and then translating will not (or equivalently, using a matrix that contains both transforms).

If you want to write your own code for this, you can do it with quaternion NLERPs. It's simple but a little tricky to get it right.