Problem with rotation around point with matrices

On 11/01/2013 at 07:36, xxxxxxxx wrote:

Hi together!

I have a problem regarding the simple rotation of a camera around a cube. This is just a testcase, so I kept it simple. The cube is in offset (0,0,1000), the camera is in (0,0,0). I want to rotate the camera around the center of the cube with the help of matrix algebra.

According to my knowledge, I have to separate the whole rotation in three steps. First translate the camera to the cube, rotate the camera, finally retranslate the camera. To get a matrix which does all that, I calculate this: [M] = [T]^-1 * [R] * [T]
C4D delievers functions to calculate the rotation and the translation matrices, which work just fine. I have to calculate [M] by myself, but this is not a big problem.
To finally rotate my camera I simply have to multiply [M] with the GetMg() of the camera.
Tell me, if I'm wrong in my approach.

So here's the code for the rotation:

def RotAroundPoint(op = c4d.BaseObject, rotPoint = c4d.Vector, H = float(), P = float(), B = float()) :  
  hpb = c4d.Vector(Rad(H), Rad(P), Rad(B))  
  rotMat = c4d.utils.HPBToMatrix(hpb)  
  print 'RotMat: {0}'.format(rotMat)  
   
  moveVec = rotPoint - op.GetMg().off  
  print 'moveVec: {0}'.format(moveVec)  
  moveMat = c4d.utils.MatrixMove(moveVec)  
  print 'moveMat: {0}'.format(moveMat)   
   
  mulRotMoveMat = rotMat  
  mulRotMoveMat = mulRotMoveMat.__rmul__(moveMat)  
  print 'mulRotMoveMat: {0}'.format(mulRotMoveMat)  
   
  complRotMoveMat = moveMat.__invert__()  
  print 'MoveMatInv: {0}'.format(complRotMoveMat)  
  complRotMoveMat = complRotMoveMat.__rmul__(mulRotMoveMat)  
  print 'complRotMoveMat: {0}'.format(complRotMoveMat)  
   
  rotMat = op.GetMg() * complRotMoveMat  
   
  op.SetMg(rotMat)  
   
  distVec = rotPoint - op.GetMg().off   
  print 'Distance: {0}'.format(distVec.GetLength())  
  c4d.EventAdd()  

The printlines are just for debugging, as you'll see later 😉

The function works, but only once. I want to call the function repeatedly and the first calculation is always correct. But each call after that returns a (partially) incorrect result.

Here is my function call:

     print 'CamMg before Rotation: {0}'.format(camMg)  
  for i in range(8) :  
      print '---------------'  
      print 'i: {0}'.format(i)          
      RotAroundPoint(cam, cube.GetMg().off, 45, 0, 0)  
      print 'CamMg: {0}'.format(cam.GetMg())  

You see, the camera should do a complete circle in 45° steps in a steady distance of 1000 to the cube. But I get the following console log:

CamMg before Rotation: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 0))  
---------------  
i: 0  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(0, 0, 1000)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 1000))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 1000))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, -1000))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (707.107, 0, 292.893))  
Distance: 1000.0  
CamMg: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (707.107, 0, 292.893))  
---------------  
i: 1  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(-707.107, 0, 707.107)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (-707.107, 0, 707.107))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (-707.107, 0, 707.107))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (707.107, 0, -707.107))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (292.893, 0, 707.107))  
Distance: 414.213562373  
CamMg: Matrix(v1: (0, 0, 1); v2: (0, 1, 0); v3: (-1, 0, 0); off: (414.214, 0, 1000))  
---------------  
i: 2  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(-414.214, 0, 0)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (-414.214, 0, 0))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (-414.214, 0, 0))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (414.214, 0, 0))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (-121.32, 0, 292.893))  
Distance: 171.572875254  
CamMg: Matrix(v1: (-0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, -0.707); off: (121.32, 0, 878.68))  
---------------  
i: 3  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(-121.32, 0, 121.32)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (-121.32, 0, 121.32))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (-121.32, 0, 121.32))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (121.32, 0, -121.32))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (50.253, 0, 121.32))  
Distance: 171.572875254  
CamMg: Matrix(v1: (-1, 0, 0); v2: (0, 1, 0); v3: (0, 0, -1); off: (0, 0, 828.427))  
---------------  
i: 4  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(0, 0, 171.573)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 171.573))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 171.573))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, -171.573))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (121.32, 0, 50.253))  
Distance: 252.834208384  
CamMg: Matrix(v1: (-0.707, 0, -0.707); v2: (0, 1, 0); v3: (0.707, 0, -0.707); off: (-121.32, 0, 778.175))  
---------------  
i: 5  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(121.32, 0, 221.825)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (121.32, 0, 221.825))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (121.32, 0, 221.825))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (-121.32, 0, -221.825))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (192.388, 0, -20.815))  
Distance: 437.921694812  
CamMg: Matrix(v1: (0, 0, -1); v2: (0, 1, 0); v3: (1, 0, 0); off: (-272.078, 0, 656.854))  
---------------  
i: 6  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(272.078, 0, 343.146)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (272.078, 0, 343.146))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (272.078, 0, 343.146))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (-272.078, 0, -343.146))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (322.33, 0, -91.883))  
Distance: 758.502625151  
CamMg: Matrix(v1: (0.707, 0, -0.707); v2: (0, 1, 0); v3: (0.707, 0, 0.707); off: (-363.961, 0, 334.524))  
---------------  
i: 7  
RotMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (0, 0, 0))  
moveVec: Vector(363.961, 0, 665.476)  
moveMat: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (363.961, 0, 665.476))  
mulRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (363.961, 0, 665.476))  
MoveMatInv: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (-363.961, 0, -665.476))  
complRotMoveMat: Matrix(v1: (0.707, 0, 0.707); v2: (0, 1, 0); v3: (-0.707, 0, 0.707); off: (577.164, 0, -62.446))  
Distance: 1117.74900609  
CamMg: Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, -117.749))  

As you can see (or recalculate) the first call is correct. The last call should result again in a camera offset of (0,0,0). You can see, that the x- and y-axis is calulated correct, but the z-axis differs. The problem is definitly the multiplication of rotMat with cam.GetMg(). When I add the following line to my function, the results are correct all over the calls:

rotMat = op.GetMg() * complRotMoveMat  
rotMat.off = op.GetMg().off + complRotMoveMat.off #the inserted line  
op.SetMg(rotMat)  

Where I get confused is: Why does it work on the first call? Do I really have to add this line? This makes completely no sense to me, because there is definitly a calculation going on in the off-Vektor when I multiply it with rotMat. So what does C4D calculate there? Please help me to clear my confusion!

Thanks in advance!

On 15/01/2013 at 04:41, xxxxxxxx wrote:

The problem changed a bit due to further research on that topic, so I opened a new thread for this: https://plugincafe.maxon.net/topic/6863/7678_rotation-of-a-camera-around-an-object