Search Home Members Contacts
About Us
Products
Downloads
Community
Support
Pages: 1 [2]
  Print  
Author Topic: Orbiting camera.(Calculating Horizontal and vertical angles)  (Read 7559 times)
Hocke
Community Member
*
Posts: 32


« Reply #20 on: September 22, 2006, 06:07:07 PM »

Great to see someone working with the space transformation and rotation problems!  Smiley I've played around some with your code and things were allright (except for the rightabove and rightbeneath problem) until I tried to change the lookat point to something else than (0, 0, 0). When the lookat is for example (5, 0, 0) all hells breake loose and nothing works correctly. How to solve this problem? Must the camera be rotated around origo and then translated back or do I miss something?

/ Håkan
Logged

Working on a 100% customizable editor for the moment...
Bierstuebl
Customers
Community Member
*****
Posts: 50


« Reply #21 on: September 25, 2006, 04:10:21 AM »

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:

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
Logged
Bierstuebl
Customers
Community Member
*****
Posts: 50


« Reply #22 on: September 25, 2006, 04:15:09 AM »

Hmm,sorry, forgot to cut out some disturbing variables from my trials to counter the flipping problem :-)

Here is a somehow cleaner code:

Code:
public void MoveCameraAroundPoint(D3DVECTOR point, float xAngle, float yAngle, float zAngle)
{
// get Vector point to camera
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);
// 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();
        }
Logged
zicmaxx
Community Member
*
Posts: 51


« Reply #23 on: September 25, 2006, 12:51:05 PM »

Why your code look like so long - -?

In my game

http://www.truevision3d.com/phpBB2/viewtopic.php?t=13213&sid=a008507634daaf592d5b5163c3ff8b0a

x = r* sin(zeta) cos(alpha)
y = r* cos(alpha)
z = r* sin(zeta) sin(alpha)

and use  Rad2Deg() but must be add offset number by
Deg = Rad2Deg()
ODeg = (Deg/100)
Deg += ODeg;

because Rad2Deg() wrong value by calculate with calculator.( specific wrong return for Sin and Cos but not Tan )

-------------------------------------
For manual move around charactor.
You must fix range no more 180 degree in Y angle couse of when you
use SetLookAt() in TVCamera you will be got " flip camera "

You must fix range or degree for  
-90(undercharactor)  0(plane) 90(overhead)

In my method for smooth camera I used TimeElapsed() * 0.00X....  for
smooth when value over fix degree
--------------------------------------
If you like my game I will show method in C++.
And in comming soon  I will be add Server/Client(by socket)  and  more GUI in my game ^^
Logged

Bierstuebl
Customers
Community Member
*****
Posts: 50


« Reply #24 on: September 26, 2006, 04:29:15 AM »

zicmaxx, just had a look at your game, looks really good. However, you just avoided all the problems I mentioned by limiting possible movement around the object (your character). I'm not coding a game, I#m coding an industrial app in which I must offer the possiblity to to absolutely freely move around any point in my 3D world. Basically you can see it as a CAD programm, where you can rotate, fly or whatever around your object - there is no ground, no terrain, no up or down. The code I posted works well for that but I can't manage to avoid the camera flipping when rotating "over" the object. That's my main problem. The best would be if one could turn of this behaviour of the camera, but I haven't found anything like this and I think it's well possible that there is no way to turn it off - so I have to counter the problem by flipping the camera 180 degrees back around the screen-axis so it can be positioned "upside down".
Logged
Bierstuebl
Customers
Community Member
*****
Posts: 50


« Reply #25 on: September 28, 2006, 10:39:32 AM »

I found out the reason for this. I run into gimbal lock not only at exatly 90° but also in a certain range around. As I us several matrices in a row with very small angles, it seems like the sin of the small angles in the matrices getting multiplied results in a number too near to 0, so I get unpredictable results here. My solution is just to jump over this "no go area", and toggle a variable for camera flipping each time I jump this no go area. Works perfectly now :-)

If anyone is really interested in the C# code (still messy up to now) just say it here.

Greetz,
Bierstuebl
Logged
zicmaxx
Community Member
*
Posts: 51


« Reply #26 on: September 28, 2006, 10:59:25 AM »

Cheesy
Logged

Javin
Customers
Community Member
*****
Posts: 994


« Reply #27 on: September 28, 2006, 11:20:44 AM »

Wow.  Talk about reinventing the wheel.

There's a much, much simpler way to do all this, folks.  Here's how I would (and have) implemented such a function.

My understanding is that you want the camera to be able to rotate around a specific point that it's "looking at."  Then, if you "turn" the camera to look at a different point, you want the camera to now rotate around the NEW point, correct?

IF this is the goal, then this is how I would go about it.  First, you constantly keep track of the camera's Position, Rotation, and Distance.

Now, your "position" is the actual point (object, collision position, whatever) that the camera is "looking at."  The Distance is the distance the camera currently is FROM that object.  The rotation is self explanitory.

While the camera is rotating, whether around an object OR while changing the lookat point, you would simply rotate the camera normally, using the changes in the mouse position to rotate it.

At the point you have the camera "lock on" to its new "lookat" point, you would store the "position" of the camera as the new collision point (ie, center of object, point on the grid, whatever) that the camera is currently looking at, then use the math library's GetDistance3D to find out the "Distance" from the point.  Since you've already got the camera's rotation stored, there's nothing further to calculate.

Now, each frame, you simply put the camera at its "position," set its rotation appropriately, and use Camera.MoveRelative -CamDistance,0,0 to move it back from this point.  

I assume this is the effect you're going for.  The ability to manually rotate the camera to lock onto, and rotate around, different objects?

-Javin
Logged

Come and join us on IRC for TV3D help!
Server: www.TrueVision3D.com:6667
Channel: #TV3DLicensed
(Open to both licensed, and non-licensed users.)
Bierstuebl
Customers
Community Member
*****
Posts: 50


« Reply #28 on: September 29, 2006, 09:29:28 AM »

Ok, good Point. But I think you run into the gimbal lock problem i mentioned quite the same way i did, only that it is harder to solve that way. Furthermore, you might get a problem if the point you rotate around is (0,0,0), but this would have to be examined. Overall, your way saves you some lines of code, because the engine will do the rest. But it may well be that doing the few necessary rotations by explicit calls may be faster than using some engine calls that may do a lot of computation.

If I find the time, I will try out your version. Right now, my version works well and the only thing I have to do is some matrix multiplication - I don't compute anything else, just ask objects for their matrix and multiply some of them :-) That the code is long and ugly is -sorry, I have to say that - because of the C# interface to TV3D 6.2. Mostly there are no real objects but structs that are passed to methods be reference parameters, which is completely unecessary and requires 3 lines of code where one would have done the same thing. For example getting the rotation matrix of an object. Unlike camera.getRotationMatrix() which returns me the D3DMATRIX struct, the tcmesh.getRotationMatrix(ref result) returns void and i have to pass a struct that will be filled. This struct must be initialised in C# in oder to be passed as reference parameter - although logically it is useless to init a variable that will only be used to take the result of a methodcall. It gets even worse for methods were 3 reference parameters are required - although only one of them is used to return a result and the others are in no way reference parameters, e.g. TVMath.engine.Math.TVVec3TransformCoord(..) or the like. Ok,I'm getting off topic here... :-) I don't want to complain, I'm quite happy I can code in C# and don't have to use VB or C++, as my complete project must be written in C# and the 3D Visualization is only a part off it.

Anyway, thanks for your approach to the problem, it's interesting. And  as I said, if I find the time, I will implement it also.

Greets, Bierstuebl
Logged
raistware
Community Member
*
Posts: 9


« Reply #29 on: October 29, 2009, 03:37:03 AM »

I found out the reason for this. I run into gimbal lock not only at exatly 90° but also in a certain range around. As I us several matrices in a row with very small angles, it seems like the sin of the small angles in the matrices getting multiplied results in a number too near to 0, so I get unpredictable results here. My solution is just to jump over this "no go area", and toggle a variable for camera flipping each time I jump this no go area. Works perfectly now :-)

If anyone is really interested in the C# code (still messy up to now) just say it here.

Greetz,
Bierstuebl


I'm at the same problem and I would be very pleased if you can post your code.

Sorry for resurrecting too old post.
Logged
luckhu
Community Member
*
Posts: 1


« Reply #30 on: October 18, 2010, 09:09:31 PM »

Hello ,thanks for all the great information you have shared!


http://www.e-luxurysin.com/
« Last Edit: October 18, 2010, 09:12:28 PM by luckhu » Logged
Pages: 1 [2]
  Print  
 
Jump to:  

Powered by SMF 1.1.3 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks