速度向量的OpenGL旋转 [英] OpenGL Rotation from Velocity Vector

查看:81
本文介绍了速度向量的OpenGL旋转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这应该很容易,但是我一直在努力寻找一个我可以理解的简单解释.我有一个要在OpenGL中表示为圆锥体的对象.该对象具有x,y,z坐标以及速度向量vx,vy和vz.圆锥体应指向速度矢量的方向.

This should be easy, but I've been all over trying to find a simple explanation that I can grasp. I have an object that I'd like to represent in OpenGL as a cone. The object has x, y, z coordinates and a velocity vector vx, vy, and vz. The cone should point in the direction of the velocity vector.

因此,我认为我的PyOpenGL代码应如下所示:

So, I think my PyOpenGL code should look something like this:

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

# do some sort of rotation here #

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

那么,那是正确的吗(到目前为止)?我可以用什么代替#在这里进行某种旋转#"?

So, is that correct (so far)? What do I put in place of the "# do some sort of rotation here #" ?

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

In my world, the Z-axis points up (0, 0, 1) and, without any rotations, so does my cone.

好的,Reto Koradi的答案似乎是我应该采用的方法,但是我不确定某些实现细节,并且我的代码无法正常工作.

Okay, Reto Koradi's answer seems to be the approach that I should take, but I'm not sure of some of the implementation details and my code is not working.

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

If I understand correctly, the rotation matrix should be a 4x4. Reto shows me how to get a 3x3, so I'm assuming that the 3x3 should be the upper-left corner of a 4x4 identity matrix. Here's my code:

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

,这是将其插入渲染代码中的方法:

and here is the way it gets inserted into the rendering code:

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

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

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

不幸的是,这不起作用.我的测试用例圆锥体无法正确指向,并且我无法确定故障模式.没有"glutMultMatrixf(transform(v)")线,圆锥体将按预期的方式沿z轴对齐.

Unfortunately, this isn't working. My test case cones just do not point correctly and I can't identify the failure mode. Without the "glutMultMatrixf(transform(v)" line, the cones align along the z-axis, as expected.

正在工作. Reto Koradi正确地识别出需要对旋转矩阵进行转置以匹配OpenGL的列顺序.代码应如下所示(在优化之前):

It's working. Reto Koradi correctly identified that the rotation matrix needed to be transposed in order to match the column order of OpenGL. The code should look like this (before optimization):

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

推荐答案

在这里要记住的一个有用概念是,线性变换也可以解释为坐标系的变化.换句话说,除了描绘坐标系统中要变换的点之外,您还可以描绘出留在原地的点,但是它们的坐标是在新的坐标系统中表示的.当查看表示变换的矩阵时,此新坐标系的基本向量是矩阵的列向量.

A helpful concept to remember here is that a linear transformation can also be interpreted as a change of coordinate systems. In other words, instead of picturing points being transformed within a coordinate system, you can just as well picture the points staying in place, but their coordinates being expressed in a new coordinate system. When looking at the matrix expressing the transformation, the base vectors of this new coordinate system are the column vectors of the matrix.

以下,将新坐标系的基本向量命名为bxbybz.由于旋转矩阵的列必须是正交的,因此bxbybz需要形成向量的正交集.

In the following, the base vectors of the new coordinate system are named bx, by and bz. Since the columns of a rotation matrix need to be orthonormal, bx, by and bz need to form an orthonormal set of vectors.

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

In this case, the original cone is oriented along the z-axis. Since you want the cone to be oriented along (vx, vy, vz) instead, we use this vector as the z-axis of our new coordinate system. Since we want an orthonormal coordinate system, the only thing left to do to obtain bz is to normalize this vector:

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

由于圆锥是旋转对称的,因此如何选择其余两个基本矢量并不重要,只要它们都正交于bz且彼此正交即可.找到给定矢量的任意正交矢量的一种简单方法是保留一个坐标0,交换其他两个坐标,并更改这两个坐标之一的符号.同样,需要对向量进行归一化.我们可以通过这种方法选择的向量包括:

Since the cone is rotationally symmetrical, it does not really matter how the remaining two base vectors are chosen, just as long as they are both orthogonal to bz, and orthogonal to each other. A simple way to find an arbitrary orthogonal vector to a given vector is to keep one coordinate 0, swap the other two coordinates, and change the sign of one of those two coordinates. Again, the vector needs to be normalized. Vectors we could choose with this approach include:

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

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

The dot product of each of these vectors with (vx, vy, vz) is zero, which means that the vectors are orthogonal.

尽管这些(或其他变体)之间的选择大部分是任意的,但必须注意不要以简并向量结尾.例如,如果vxvy都为零,则使用这些向量中的第一个将是不好的.为了避免选择(接近的)简并向量,一种简单的策略是,如果vz小于vxvy,则使用这三个向量中的第一个,否则使用其他两个向量.

While the choice between these (or other variations) is mostly arbitrary, care must be taken to not end up with a degenerate vector. For example if vx and vy are both zero, using the first of these vector would be bad. To avoid choosing a (near) degenerate vector, a simple strategy is to use the first of these three vectors if vz is smaller than both vx and vy, and one of the other two otherwise.

有了两个新的基本向量,第三个是其他两个的叉积:

With two new base vectors in place, the third is the cross product of the other two:

bx = by x bz

剩下的就是用列向量bxbybz填充旋转矩阵,并且旋转矩阵是完整的:

All that's left is to populate the rotation matrix with column vectors bx, by and bz, and the rotation matrix is complete:

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

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

If you need a 4x4 matrix, e.g. because you are using the legacy fixed function OpenGL pipeline, you can extend this to a 4x4 matrix:

    [ 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 ]

这篇关于速度向量的OpenGL旋转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆