从速度矢量OpenGL旋转

时间:2014-07-11 19:34:40

标签: python opengl

这应该很容易,但我一直试图找到一个我能掌握的简单解释。我有一个对象,我想在OpenGL中表示为锥形。该对象具有x,y,z坐标和速度矢量vx,vy和vz。锥体应指向速度矢量的方向。

所以,我认为我的PyOpenGL代码应该是这样的:

glPushMatrix()
glTranslate(x, y, z)
glPushMatrix()

# do some sort of rotation here #

glutSolidCone(base, height, slices, stacks)
glPopMatrix()
glPopMatrix()

那么,这是正确的(到目前为止)?我该怎样代替"#在这里进行某种轮换#" ?

在我的世界中,Z轴指向上方(0,0,1)并且没有任何旋转,我的锥体也是如此。


好的,Reto Koradi的答案似乎是我应该采取的方法,但我不确定某些实施细节,而且我的代码无效。

如果我理解正确,旋转矩阵应为4x4。 Reto向我展示了如何获得3x3,所以我假设3x3应该是4x4单位矩阵的左上角。这是我的代码:

import numpy as np

def normalize(v):
    norm = np.linalg.norm(v)
    if norm > 1.0e-8:  # arbitrarily small
        return v/norm
    else:
        return v

def transform(v):
    bz = normalize(v)
    if (abs(v[2]) < abs(v[0])) and (abs(v[2]) < abs(v[1])):
        by = normalize(np.array([v[1], -v[0], 0]))
    else:
        by = normalize(np.array([v[2], 0, -v[0]]))
        #~ by = normalize(np.array([0, v[2], -v[1]]))

    bx = np.cross(by, bz)
    R =  np.array([[bx[0], by[0], bz[0], 0],
                   [bx[1], by[1], bz[1], 0],
                   [bx[2], by[2], bz[2], 0],
                   [0,     0,     0,     1]], dtype=np.float32)

    return R

以下是插入渲染代码的方式:

glPushMatrix()
glTranslate(x, y, z)
glPushMatrix()

v = np.array([vx, vy, vz])
glMultMatrixf(transform(v))

glutSolidCone(base, height, slices, stacks)
glPopMatrix()
glPopMatrix()

不幸的是,这不起作用。我的测试用例锥体没有正确指出,我无法识别故障模式。没有&#34; glutMultMatrixf(transform(v)&#34;线,锥体沿z轴对齐,如预期的那样。


它在工作。 Reto Koradi正确地确定了旋转矩阵需要转置以匹配OpenGL的列顺序。代码应如下所示(优化前):

def transform(v):
    bz = normalize(v)
    if (abs(v[2]) < abs(v[0])) and (abs(v[2]) < abs(v[1])):
        by = normalize(np.array([v[1], -v[0], 0]))
    else:
        by = normalize(np.array([v[2], 0, -v[0]]))
        #~ by = normalize(np.array([0, v[2], -v[1]]))

    bx = np.cross(by, bz)
    R =  np.array([[bx[0], by[0], bz[0], 0],
                   [bx[1], by[1], bz[1], 0],
                   [bx[2], by[2], bz[2], 0],
                   [0,     0,     0,     1]], dtype=np.float32)

    return R.T

1 个答案:

答案 0 :(得分:0)

这里要记住的有用概念是线性变换也可以解释为坐标系的变化。换句话说,不是描绘在坐标系内变换的点,而是可以描绘留在原点的点,但是它们的坐标在新的坐标系中表示。当观察表示变换的矩阵时,这个新坐标系的基矢量是矩阵的列矢量。

在下文中,新坐标系的基矢量名为bxbybz。由于旋转矩阵的列需要是正交的,bxbybz需要形成一组标准的矢量。

在这种情况下,原始锥体沿z轴定向。由于您希望锥体沿(vx, vy, vz)定向,我们使用此向量作为新坐标系的z轴。由于我们需要一个标准正交坐标系,因此获得bz唯一要做的就是对这个向量进行标准化:

               [vx]
bz = normalize([vy])
               [vz]

由于圆锥体是旋转对称的,所以选择剩余的两个基本矢量并不重要,只要它们都与bz正交,并且彼此正交。找到给定矢量的任意正交矢量的一种简单方法是保持一个坐标0,交换另外两个坐标,并改变这两个坐标之一的符号。同样,向量需要标准化。我们可以选择这种方法的载体包括:

               [ vy]                  [ vz]                  [ 0 ]
by = normalize([-vx])  by = normalize([ 0 ])  by = normalize([ vz])
               [ 0 ]                  [-vx]                  [-vy]

每个这些向量与(vx, vy, vz)的点积为零,这意味着向量是正交的。

虽然这些(或其他变体)之间的选择大多是任意的,但必须注意不要以简并向量结束。例如,如果vxvy都为零,则使用这些向量中的第一个将是错误的。为避免选择(近)退化向量,一个简单的策略是,如果vz小于vxvy,则使用这三个向量中的第一个,另外两个中的一个否则。

有两个新的基本向量,第三个是另外两个的叉积:

bx = by x bz

剩下的就是用列向量bxbybz填充旋转矩阵,旋转矩阵就完成了:

    [ bx.x by.x bz.x ]
R = [ bx.y by.y bz.y ]
    [ bx.z by.z bz.z ]

如果您需要4x4矩阵,例如因为您正在使用传统的固定功能OpenGL管道,所以您可以将其扩展为4x4矩阵:

    [ bx.x by.x bz.x 0 ]
R = [ bx.y by.y bz.y 0 ]
    [ bx.z by.z bz.z 0 ]
    [  0    0    0   1 ]