We've tried to figure out for quite a while in the #python
channel how to compute the eye/target/up vectors out of a view matrix using sympy. One possible way to do it could be:
from sympy import *
from pprint import pprint
v1, v2, v3, v4 = symbols('v1 v2 v3 v4')
v5, v6, v7, v8 = symbols('v5 v6 v7 v8')
v9, v10, v11, v12 = symbols('v9 v10 v11 v12')
v13, v14, v15, v16 = symbols('v13 v14 v15 v16')
V = Matrix([
[v1, v2, v3, v4],
[v5, v6, v7, v8],
[v9, v10, v11, v12],
[v13, v14, v15, v16],
])
u1, u2, u3 = symbols('u1 u2 u3', real=True)
t1, t2, t3 = symbols('t1 t2 t3', real=True)
e1, e2, e3 = symbols('e1 e2 e3', real=True)
U = Matrix([u1, u2, u3])
T = Matrix([t1, t2, t2])
E = Matrix([e1, e2, e3])
def calculate_view_matrix(up, eye, target):
zaxis = (eye - target).normalized()
xaxis = up.cross(zaxis).normalized()
yaxis = zaxis.cross(xaxis)
orientation = Matrix([
[xaxis[0], yaxis[0], zaxis[0], 0],
[xaxis[1], yaxis[1], zaxis[1], 0],
[xaxis[2], yaxis[2], zaxis[2], 0],
[0, 0, 0, 1],
])
translation = Matrix([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[-eye[0], -eye[1], -eye[2], 1],
])
return orientation * translation
print(V - calculate_view_matrix(U, E, T))
s = solve([
V - calculate_view_matrix(U, E, T),
U.norm() - 1,
T.norm() - 1],
[u1, u2, u3, t1, t2, t3, e1, e2, e3])
print(s)
But for some reason that script has been running for ~20 minutes and sympy hasn't been able to give any solution so far.
Another attempt has also been trying to simplify the above generic problem to something simpler as how would you compute the up vector?
In a simpler context, the problem definition would be something like this:
u,z,x
are 3d vectors which forms an orthonormal basis.z, x
are constant vectorsu
is the unknown vector
And the equation to solve this:
u.cross(z).normalized() - x
If you tried to solve a simple particular case of the above generic equation like this...
from sympy import *
u1,u2,u3=symbols('u1 u2 u3', real = True)
x=Matrix([1,0,0])
z=Matrix([0,0,1])
u=Matrix([u1,u2,u3])
print(solve(u.cross(z).normalized() - x, u))
you'd get NotImplementedError: could not solve u2 - Abs(u2)
.
NS: Thing is, in order to extract the inputs from the view matrix is required than the function computing the matrix be injective or bijective, otherwise the initial information will be lost. If you don't add any constraints the above functions are definitely not injectives because at the moment which is using a normalize operation the function becomes automatically not injective anymore, for instance:
a) normalize(x) = x/|x|
b) To prove normalize is injective then normalize(a)=normalize(b) should give a=b
c) normalize(a)=normalize(b) => a/|a|=b/|b| , which is not true then normalize is not injective
Of course, this could be trivially proved just saying than infinitelly vectors can provide the same normalized vector.
That's the reason why there has been added few constraints to calculate_view_matrix
. Ie: U.norm() - 1
, T.norm() - 1
. Theorically, that should grant the calculate_view_matrix
to become injective... (or not :))
So the main question would be, how can you constrain/modify properly the calculate_view_matrix
so it can calculate the eye/target/up vectors out of the view matrix?