我正试图在opengl中渲染3D激光束。我有两个点(p1,p2)和一个由p1和p2之间的距离缩放的三边圆柱体。问题是我不能让气缸正确旋转。我尝试使用atan2来计算三个轴的角度并将它们应用到矩阵中,到目前为止还没有成功。气缸根本不跟随这些点。这就是我完成旋转计算的方法:
p3 = p2 - p1
rotX = atan2(p3.y, p3.z)
rotY = atan2(p3.x, p3.z)
rotZ = atan2(p3.x, p3.y)
matrix.rotate(rotX, rotY, rotZ)
答案 0 :(得分:1)
这是一些线性代数很长的情况之一。你根本不需要三角学。三角测量是关于角度的,你正在做的是将直角坐标转换为角度,然后再转换回直角坐标。这两次转换是不必要的。
让我们定义v = p2 - p1。
假设你的圆柱沿着Z轴,从(0,0,0)到(0,0,1)。我们正在尝试创建一个矩阵A,它为我们提供了以下转换:
A * (0, 0, 1) = v
好吧,一旦你把它写出来,看起来很简单,不是吗!因为将矩阵乘以基矢量,所以给出了一个列向量。所以v必须是矩阵的一列。
A = [ ? ? v.x ]
[ ? ? v.y ]
[ ? ? v.z ]
现在我们只选择另外两个归一化并与v正交的列向量,这样我们就可以保留激光的横截面形状。这很容易。下面是一些代码,因为它将用GLSL编写(你可以使用带有C ++的glm或带有JavaScript的gl-matrix来获得类似的语法)。
mat3 create_laser_matrix(vec3 v) {
// Find a vector, ref, not parallel to v
vec3 vmag = abs(v);
vec3 ref;
if (vmag.x <= vmag.y && vmag.x <= vmag.z) {
ref = vec3(1.0, 0.0, 0.0);
} else if (vmag.y <= vmag.z) {
ref = vec3(0.0, 1.0, 0.0);
} else {
ref = vec3(0.0, 0.0, 1.0);
}
// Use ref to create two unit vectors, u1, u2, so {v, u1, u2} are orthogonal
vec3 utemp = cross(v, ref);
vec3 u1 = normalize(cross(v, utemp));
vec3 u2 = normalize(cross(v, u1));
return mat3(u1, u2, v);
}
扩展数学:三角函数允许我们在角度和直角坐标之间进行转换,反之亦然,但事实证明我们根本不需要这样做。 “旋转矩阵”只是一种正交矩阵(一个具有行列式1而不是-1),而正交矩阵只是列向量正交的矩阵,这就意味着任意两列的点积向量为零。不需要三角学。我们并不完全遵循正交矩阵,因为我们需要“拉伸”激光来连接两个点,但大多数相同的数学都适用。