2014-07-11 71 views
1

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

所以,我觉得我的PyOpenGL代码应该是这个样子:

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

# do some sort of rotation here # 

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

那么,是正确的(迄今为止)?我用什么来代替“#在这里做某种旋转#”?

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


好吧,雷托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() 

不幸的是,这是行不通的。我的测试案例锥体只是没有正确指出,我无法识别失败模式。如果没有“glutMultMatrixf(变换(V)”行,锥沿z轴对齐,符合市场预期。


它的工作。雷托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 

回答

0

一个有用的概念,这里要记住的是,线性变换也可以被解释为坐标系的变化。换句话说,而不是描绘点在坐标系统内转换,你可以很好地描绘点的位置,但它们的位置坐标以新的坐标系表示。当查看表达变换的矩阵时,这个新坐标系的基向量是矩阵的列向量。

在下面,新坐标系的基矢量被命名为bx,bybz。由于旋转矩阵的列需要是正交的,所以bx,bybz需要形成正交的向量集合。

在这种情况下,原始锥体沿着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 ] 
+0

不旋转矩阵需要一个4x4矩阵(我假设我应该使用glMultMatrixf呼叫)?速度矢量为[0,0,0]时的情况如何?我需要特殊情况下的那种情况吗? – user2483736

+0

是的,如果您使用的是固定管道,则必须将其扩展到4x4。如果您使用着色器(在Core Profile中需要),则可以将3x3矩阵传递到着色器中。 –

+0

您在上面添加的代码看起来很合理。根据OpenGL绑定处理矩阵的方式,您可能需要按转置顺序编写元素。至少在本地接口中,OpenGL期望矩阵按列主要顺序传入。为了调试,我将从非常简单的案例开始,并查看结果矩阵中的值。例如。用一个指向'z'方向的矢量,你应该能够通过查看矩阵来判断它是否正确。 –