I'm also playing around to build a viewer where the camera can be moved around any chosen point in my 3D-world. However, I've chosen a sligthly different approach.
So basically what I do is:
1: Get the vector a from camera to rotation center (this is my new z-axis)
2: rotate it with the inversion of the rotation matrix of the camera to get vector a' in the virtual coordinate system of the camera. I first thougt the camera's rotation matrix would give me the way to transform a the world coordinate system to the camera's virtual coordinate system - but it's exactly the opposite, so you have to use the inversion of the camera's rotation matrix to get from world to camera coordinate system.
3: do any translation to a' (optional)
4: rotate a' around x, y and z axis by using TVMath.TVMatrixRotationYawPitchRoll, which returns me a rotation matrix for these angles so that I can apply it to the vector a'
5: go back to world coordinate system by using camera's rotation matrix on a' to get a again.
6: set camera position to the new vector a and make it look to the rotation center again. Here's a bit of code:
public void MoveCameraAroundPoint(D3DVECTOR point, float xAngle, float yAngle, float zAngle)
{
// get Vector point to camera
float d1_alt=0;
float d2_alt=0;
float d1_neu=0;
float d2_neu=0;
TVCamera camera = engine.Scene.GetCamera();
D3DVECTOR camPos = camera.GetPosition();
D3DVECTOR radiusWorld = engine.Globals.Vector(camPos.x - point.x, camPos.y - point.y, camPos.z - point.z);
d1_alt = radiusWorld.x;
d2_alt = radiusWorld.y;
// Rotate this Vector into the virtual coordinate system of the Camera
D3DMATRIX toWorldMatrix = camera.GetRotationMatrix();
float det = 0;
// dummy init the toVirtualMatrix (because it's needed as ref parameter)
D3DMATRIX toVirtualMatrix = camera.GetRotationMatrix();
engine.Math.TVMatrixInverse(ref toVirtualMatrix, ref det, ref toWorldMatrix);
// dummy init the radiusVirtual
D3DVECTOR radiusVirtual = engine.Globals.Vector(0, 0, 0);
engine.Math.TVVec3TransformCoord(ref radiusVirtual, ref radiusWorld, ref toVirtualMatrix);
D3DMATRIX rotMatrix = camera.GetRotationMatrix();
// rotate around the axis with given angles
engine.Math.TVMatrixRotationYawPitchRoll(ref rotMatrix, xAngle, yAngle, zAngle);
D3DVECTOR radiusVirtualRotated = engine.Globals.Vector(0, 0, 0);
engine.Math.TVVec3TransformCoord(ref radiusVirtualRotated, ref radiusVirtual, ref rotMatrix);
// Console.WriteLine("x,y,z: {0}, {1}, {2}", radiusVirtualRotated.x,radiusVirtualRotated.y, radiusVirtualRotated.z);
D3DVECTOR radiusWorldRotated = engine.Globals.Vector(0, 0, 0);
engine.Math.TVVec3TransformCoord(ref radiusWorldRotated, ref radiusVirtualRotated, ref toWorldMatrix);
engine.Scene.SetCamera(point.x + radiusWorldRotated.x,
point.y + radiusWorldRotated.y,
point.z + radiusWorldRotated.z,
point.x, point.y, point.z);
camera = engine.Scene.GetCamera();
}
engine is a Singleton-class from me, so you have to use your normal way to get to your instance of TVEngine and TVScene :-) ALso note the dummy-inits of the D3DMATRIX structs. It's the easiest way I found yet to init such a struct so it can be used as a reference parameter. Unfortuneately in the C# version of TV 6.2 nearly all methods are requesting reference parameters which in fact don't need to be reference parameters as they are never changed insde the method. Bu that's a different story :-)
This works perfectly except for one thing: the "flipping" of the camera if you "fly" over your rotation center. I don't mean the fact that you can't have an exact view on your rotation center from above or beneath. I'm talking about the camera rotating around the screen-axis in order to always stay "heads up". Hmm, difficult to discribe here :-) I hope you can unstand what I'm trying to say, I think it's the same problem scottwinch mentioned before. I don't want the camera to always stay "heads up" if i fly with it around an object. This might be useful for shooter games etc where you don't want to see your world upside down, but it's really disturbing for my goal to build a viewer where I can freely fly around any object.
In my first version of my viewer, I also used the TVMath.MoveAroundPoint method to get new camera position on basis of increasing and decreasing an absolut vertical an horizontal angle. This way, I was able to counter the problem of the flipping camera by checking if the vertical angle is between 90 and 270 degrees and rotate the camera 180 degrees around its z-axis so that it is "heads down" again. With the above approach of working with rotation matrix and relative angles, I can no longer check this.
Does anybody have an idea how to avoid these camera flipping? Is there a way to disable it that I just haven't found yet? What criteria is exactly used by the engine to detect if it should flip the camera? I I knew this, I could recode it to counter the problem.
Many thanks in advance,
Bierstuebl