# 3D Camera transformation versus Object transformation

A 3D camera is located at position $(eye_x,eye_y,eye_z)$ and looking at some object located at position $(0,0,0)$.

How can I achieve the same visual result but rotating the object (and having a static camera) instead of translating the camera around?

For example, if the camera eye is located at position $(2,2,2)$ looking at $(0,0,0)$, I guess I should rotate at least the object around Y axis 45° degrees. However, I don't know what calculations starting from the camera vectors (eye,at) should I apply in order to get there.

This is the camera transformation:

This is the desired transformation:

• I’m not positive I understand “the same visual result”. Or the question being asked. Are you not just giving the coordinates of “eye” in your example? I don’t see what transformation you want to do. – rschwieb Dec 30 '17 at 15:46
• @rschwieb I think he's asking how to obtain the rotation of the object so that the camera's output remains the same even if the camera moves. OP correct me if I understood wrong. – Rohat Kılıç Dec 30 '17 at 15:50
• @RohatKılıç Exactly. I want to see the same output in my window, but instead of moving the camera what I want to move is only the object. – Andrés Dec 30 '17 at 15:54

Prepare yourself for long and detailed explanation.

Let W be the transformation of the target object and V is the view matrix obtained from the transformation of the camera:

$W=\begin{bmatrix} mR_x&mR_y&mR_z&0\\ mU_x&mU_y&mU_z&0\\ mL_x&ML_y&mL_z&0\\ mT_x&mT_y&mT_z&1\\ \end{bmatrix} \ \ \ \ , \ \ \ \ \ V=\begin{bmatrix} cR_x&cU_x&cL_x&0\\ cR_y&cU_y&cL_y&0\\ cR_z&cU_z&cL_z&0\\ -(cR\cdot cT)&-(cU\cdot cT)&-(cL\cdot cT)&1\\ \end{bmatrix}$

where

• mR, mU and mL are the local right, up and look vectors (axis), mT is the translation (at, in your case) vector of the target object;
• cR, cU and cL are the local right, up and look vectors (axis), cT is the translation (eye, in your case) vector of the camera.

Since the camera always looks at the the object, the following should be used to obtain the cR, cU and cL vectors of the camera:

$vU = (0, 1, 0)\\ cL = normalize(mT-cT) \\ cR = normalize(vU \times cL) \\ cU=normalize(cL\times cR)$

NOTE: "$\times$" indicates a cross-product and "$\cdot$" indicates a dot-product.

To get the same image after projection, the multiplication of W (world) and V (view) matrices should remain the same (i.e. $W_0 \times V_0 = W_n \times V_n$). Note that I assumed the projection matrix does not change.

So you have initial world and view matrices, i.e. $W_0$ and $V_0$. Thus you also have $W_0 \times V_0$.

Then you moved the camera to somewhere else (i.e. cT is changed) but the target object is still at the origin. So you need to re-build the V matrix as I explained above. Let's name it as $V_n$.

Thus,

$W_n \times V_n=W_0 \times V_0 \\ \Rightarrow W_n=W_0 \times V_0 \times V_n^{-1}$

where $V_n^{-1}$ is the inverse of $V_n$; and $W_n$ is the new world matrix of the target object to guarantee the same image after projection.

If you extract the local axis vectors from $W_n$ then you can find the rotation angles compared to the initial state:

$mR_n \cdot mR_0 = |mR_n| \ |mR_0| \ \cos\alpha\\ mU_n \cdot mU_0 = |mU_n| \ |mU_0| \ \cos\beta\\ mL_n \cdot mL_0 = |mL_n| \ |mL_0| \ \cos\theta$

Note that the distance between camera and the target object should be the same if you want to only rotate the target object. Or else you'll also need to re-position it. The updated translation vector can be extracted from $W_n$ as well.

• Thank you sir. This is my implementation: freetexthost.com/vj3nd1ttxe But it doesn't work. Could you take a look to see if I a mistyped something? – Andrés Dec 30 '17 at 21:59
• @Andrés Oh, it seems that you're working on an Android-OpenGL project. I didn't know that. I'm a DirectX-guy, so the calculations above are based on left-handed 3D coordinate systems and row-major matrices. But OpenGL's 3D coordinate system is right-handed and its matrix structure is column-major. Thus; 1: cL should be multiplied by -1; 2: '-' signs in the last row of V matrix should be removed and 3: all the matrices should be transposed before using. – Rohat Kılıç Dec 31 '17 at 6:04
• @Andrés PS: Please note that if you want the object to look at the camera at all times the calculations become even simpler. But I think it's not guaranteed in your case. – Rohat Kılıç Dec 31 '17 at 6:11

If you always keep your object on the Z-axis and your camera on $(0,0,0)$ then the maths simplifies alot.

Say you want the same visual result as moving the camera with a vector M. this would be the same as moving the object the opposite direction $(W=-M)$.

$W$ can be writen as $Z+W_{xy}$ where $Z$ is a vector on the Z-axis and $W_{xy}$ is a vector in the XY-plane. We can do the same for $W_{xy}$ and split it into it's x & y component, $W_x$ & $W_y$.

We want the same visual result as moving the object with $W, \; (Object+W)$.

Step 1 $$Result = Object + W = (Object + Z) + W_{xy}$$ $(Object + Z)$ is just moving the object closer or further away from the camera. So we just have to scale the object with a factor of $\frac{||Object +Z||}{||Object||}$

now to calculate the $+ W_{xy}$ or $+W_x+W_y$ we have to do some trigonometry.

worth noting $W_x$ and $W_y$ are perpendicular to $(Object + Z)$

so moving the object perpendicular with the way we are looking at it is the same as rotating it and moving it backwards. 'rotating' in the sence of around it's own axis. (see red arrow for clarification)

Step 2 $$(Object + Z) + W_x$$ As seen above this is just a rotation of the object and a scaling. $L$ can be calculated using Pythagoras ,$L^2=||(Object + Z)||^2+||W_x||^2$. This allows us the calculate the angle with, $cos(\alpha) = \frac{||Object + Z||}{L}$. the scaling is just like for Z, $f=\frac{L}{||Object + Z||}$. (!!) this rotation is around the objects y-axis.

Step 3 $$(Object + Z + W_x) + W_y$$ analog to step 2.

because we always keep our object on the Z axis. we only need 1 number to know where our object is, let's call it $d$. this also means that $-M = W = (w_x,w_y,z)$ for step 1 we need to scale our object with a factor $S_z=\frac{d+z}{d}, Object \rightarrow S_z \cdot Object$ and we need to change $d$ to $d+z$

for step 2&3 we need to scale and rotate around the objects y-axis (for step2) and x-axis (for step 3) the're a lot of ways of doing this i would suggest using rotation matrices. the angle and scale for step 2 are $\alpha_1 = \arccos(\frac{d}{\sqrt{d^2+w_x^2}})$ and $S_x = \frac{\sqrt{d^2+w_x^2}}{d}$ also $d$ changes to $\sqrt{d^2+w_x^2}$ the same needs to be done for step 3

summary

$$-M = W = (z,w_x,w_y)$$ $$S_z = \frac{z+d}{d}$$ $$L_x = \sqrt{(d+z)^2 + w_x^2}$$ $$\alpha_1 = \arccos(\frac{d+z}{L_x})$$ $$S_x = \frac{L_x}{d+z}$$ $$L_y = \sqrt{L_x^2 + w_y^2}$$ $$\alpha_2 = \arccos(\frac{L_x}{L_y})$$ $$S_y = \frac{L_y}{L_x}$$ $$S = S_z \cdot S_x \cdot S_y = \frac{L_y}{d}$$ $$Object \mbox{ at }(0,0,d) \rightarrow (Rot_x(\alpha_2) \cdot Rot_y(\alpha_1) \cdot S \cdot Object)\mbox{ at }(0,0,L_y)$$

After struggling with the problem I found a solution that may not be optimal but at least solves the use case.

Here are the steps to rotate an object instead of moving the camera and have the same result:

1. Get the matrix of the camera:

Matrix.setLookAtM(cameraMatrix, 0, camera.xPos, camera.yPos, camera.zPos, camera.xView, camera.yView, camera.zView, camera.xUp, camera.yUp, camera.zUp);

2. Extract the rotation matrix:

float[] rotationMatrix = extractRotationMatrix(cameraMatrix); // here it's possible to extract axis and angle from rotationMatrix

3. Apply transformation to object:

object.applyRotation(rotationMatrix); // ModelMatrix=TranslationMatrix X ScaleMatrix X RotationMatrix