这应该很容易,但我一直试图找到一个我能掌握的简单解释。我有一个对象,我想在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
答案 0 :(得分:0)
这里要记住的有用概念是线性变换也可以解释为坐标系的变化。换句话说,不是描绘在坐标系内变换的点,而是可以描绘留在原点的点,但是它们的坐标在新的坐标系中表示。当观察表示变换的矩阵时,这个新坐标系的基矢量是矩阵的列矢量。
在下文中,新坐标系的基矢量名为bx
,by
和bz
。由于旋转矩阵的列需要是正交的,bx
,by
和bz
需要形成一组标准的矢量。
在这种情况下,原始锥体沿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)
的点积为零,这意味着向量是正交的。
虽然这些(或其他变体)之间的选择大多是任意的,但必须注意不要以简并向量结束。例如,如果vx
和vy
都为零,则使用这些向量中的第一个将是错误的。为避免选择(近)退化向量,一个简单的策略是,如果vz
小于vx
和vy
,则使用这三个向量中的第一个,另外两个中的一个否则。
有两个新的基本向量,第三个是另外两个的叉积:
bx = by x bz
剩下的就是用列向量bx
,by
和bz
填充旋转矩阵,旋转矩阵就完成了:
[ 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 ]