如何使用sympy从视图矩阵中提取眼睛/目标/向上?

BPL*_*BPL 10 python 3d geometry matrix sympy

我们试图在#python通道中弄清楚如何使用sympy从视图矩阵中计算出眼睛/目标/向上矢量.一种可行的方法可能是:

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)
Run Code Online (Sandbox Code Playgroud)

但出于某种原因,脚本已经运行了大约20分钟,并且到目前为止,sympy还没能提供任何解决方案.

另一种尝试也试图将上述通用问题简化为更简单的方法,如何计算向上向量?

在更简单的上下文中,问题定义将是这样的:

  1. u,z,x是形成标准正交基础的 3d向量.
  2. z, x 是常数向量
  3. u 是未知的向量

以及解决这个问题的等式:

u.cross(z).normalized() - x
Run Code Online (Sandbox Code Playgroud)

如果你试图像这样解决上述通用方程的一个简单特例...

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))
Run Code Online (Sandbox Code Playgroud)

你会得到的NotImplementedError: could not solve u2 - Abs(u2).

NS:为了从视图矩阵中提取输入,需要比计算矩阵的函数是内射或双射的,否则初始信息将丢失.如果你没有添加任何约束,上面的函数绝对不是内射函数,因为在使用规范化操作的那一刻,函数不再是自动的,例如:

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
Run Code Online (Sandbox Code Playgroud)

当然,这可以简单地证明只是说infinitelly矢量可以提供相同的标准化矢量.

这就是为什么增加了一些约束的原因calculate_view_matrix.即:U.norm() - 1,T.norm() - 1.理论上,这应该授予calculate_view_matrix变得无形......(或不:)

所以主要的问题是,如何正确地约束/修改,calculate_view_matrix以便它可以从视图矩阵中计算出眼睛/目标/向上矢量?

cop*_*roc 1

除了拼写错误 ( T = Matrix([t1, t2, t2])) 之外,您的 Ansatz 中的起床、眼睛和目标矢量从视图矩阵返回还存在几个缺陷:

  • 视图矩阵描述了 3D 中的刚性变换,它只有 6 个自由度(3 轴旋转,3 轴平移)。这大致意味着 16 个值中v1, v2, ..., v16只能选择 6 个(或多或少是任意的),其他值是相关的或以任何方式确定(例如v4 = v8 = v12 = 0v16 = 1v3**2 = 1 - v1**2 - v2**2、 ...)。因此,一般来说,矩阵差分的方程是矛盾的。
  • 即使需要U.norm() - 1 = 0上矢量U可以取无限多个值(未确定一个角度)。为了将可能的解决方案减少U到有限多种情况,可以添加条件U*(E-T) = 0
  • 条件T.norm() - 1 = 0不对。可以T - E/应该要求(视图的方向)具有 length 1

U, E, T总而言之,我没有看到可以使用方程和 sympy 从视图矩阵计算修复 Ansatz st 的方法。但U, E, T可以很容易地从视图矩阵中提取:

  • U可以从第二列读取标准化的(满足上述要求)
  • -E可以从最后一行读取
  • E - T可以从第三列读取标准化视图向量

在 sympy/Python 代码中:

def calculate_up_eye_target(viewMat):
  eye = -viewMat[3,0:3].T
  target = eye - viewMat[0:3,2]
  up = viewMat[0:3,1]
  return up, eye, target
Run Code Online (Sandbox Code Playgroud)