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://developers.maxon.net/forum/topic/6863/7678_rotation-of-a-camera-around-an-object