[英]Need rotation matrix for opengl 3D transformation
问题是我在3D空间中有两个点,其中y +是向上的,x +是向右的,而z +是朝向你的。 我想在它们之间定位一个圆柱体,它是两个点之间距离的长度,因此它的两个中心端都接触这两个点。 我将气缸转换到两点中心的位置,我需要帮助提出一个旋转矩阵应用于气缸,以便它以正确的方式定向。 我对整个事物的转换矩阵如下所示:
平移(中心点)* rotateX(有些X度)* rotateZ(有些Z度)
翻译最后应用,这样我可以在翻译之前将其转换为正确的方向。
以下是我迄今为止所做的事情:
mat4 getTransformation(vec3 point, vec3 parent)
{
float deltaX = point.x - parent.x;
float deltaY = point.y - parent.y;
float deltaZ = point.z - parent.z;
float yRotation = atan2f(deltaZ, deltaX) * (180.0 / M_PI);
float xRotation = atan2f(deltaZ, deltaY) * (180.0 / M_PI);
float zRotation = atan2f(deltaX, deltaY) * (-180.0 / M_PI);
if(point.y < parent.y)
{
zRotation = atan2f(deltaX, deltaY) * (180.0 / M_PI);
}
vec3 center = vec3((point.x + parent.x)/2.0, (point.y + parent.y)/2.0, (point.z + parent.z)/2.0);
mat4 translation = Translate(center);
return translation * RotateX(xRotation) * RotateZ(zRotation) * Scale(radius, 1, radius) * Scale(0.1, 0.1, 0.1);
}
我尝试了下面给出的解决方案,但它似乎根本不起作用
mat4 getTransformation(vec3 parent, vec3 point)
{
// moves base of cylinder to origin and gives it unit scaling
mat4 scaleFactor = Translate(0, 0.5, 0) * Scale(radius/2.0, 1/2.0, radius/2.0) * cylinderModel;
float length = sqrtf(pow((point.x - parent.x), 2) + pow((point.y - parent.y), 2) + pow((point.z - parent.z), 2));
vec3 direction = normalize(point - parent);
float pitch = acos(direction.y);
float yaw = atan2(direction.z, direction.x);
return Translate(parent) * Scale(length, length, length) * RotateX(pitch) * RotateY(yaw) * scaleFactor;
}
运行上面的代码后,我得到了这个:
每个黑点都是一个点,其父级是产生它的点(前面的那个)我希望分支适合点。 基本上我正在尝试为随机树生成实现空间定殖算法。 我得到了大部分,但我想将树枝映射到它,所以看起来不错。 我可以使用GL_LINES来建立一个通用的连接,但如果我得到这个工作,它看起来会更漂亮。 这里解释了算法。
这是我想要做的事情的图像(原谅我的绘画技巧)
嗯,有任意数量的旋转矩阵满足您的约束。 但任何人都会这样做。 我们不是试图找出特定的旋转,而是直接写下矩阵。 假设您的圆柱体在未应用变换时,其轴线沿Z轴。 因此,您必须将局部空间Z轴转换为这两个点之间的方向。 即z_t = normalize(p_1 - p_2)
,其中normalize(a) = a / length(a)
。
现在我们只需要使它成为一个完整的三维坐标基础。 我们从一个与z_t不平行的任意向量开始。 比如,(1,0,0)或(0,1,0)或(0,0,1)之一; 用标产品·
(也称为内部,或内积)与z_t并使用其绝对值最小的向量,我们称之为载体u
。 在伪代码中:
# Start with (1,0,0)
mindotabs = abs( z_t · (1,0,0) )
minvec = (1,0,0)
for u_ in (0,1,0), (0,0,1):
dotabs = z_t · u_
if dotabs < mindotabs:
mindotabs = dotabs
minvec = u_
u = minvec_
然后,您正交化该向量,产生局部y变换y_t = normalize(u - z_t · u)
。
最后通过乘以叉积x_t = z_t × y_t
创建x变换
要将圆柱体移动到位,请将其与匹配的平移矩阵组合。
转换矩阵实际上只是你从“来自”空间的轴,就像从另一个空间看到的那样。 因此,得到的矩阵,即您正在寻找的旋转矩阵,只是矢量x_t,y_t和z_t并排作为矩阵。 OpenGL使用所谓的均匀矩阵,因此您必须使用0,0,0,1最底行和最右列将其填充为4×4形式。
你可以加载到OpenGL; 如果使用固定功能使用glMultMatrix来应用旋转,或者如果使用着色器乘以矩阵,则最终会传递给glUniform。
用具有其两端,我称之为一个单位长度的圆筒开始C1
,在原点(请注意,您的图片表明了你的汽缸都有它的起源中心 ,但你可以很容易地变换一下我开头)。 另一端,我称之为C2
,然后是(0,1,0)
。
我想打电话给你的两个点在世界坐标P1
和P2
,我们要找到C1
上的P1
和C2
至P2
。
首先将圆柱体转换为P1
,然后将C1
成功定位到P1
。
然后按distance(P1, P2)
缩放圆柱体,因为它最初的长度为1
。
可以使用球面坐标计算剩余旋转。 如果您不熟悉这种类型的坐标系:它就像GPS坐标:两个角度; 一个围绕极轴(在你的情况下是世界的Y轴),我们通常称之为偏航 ,另一个是俯仰角(在你的情况下是模型空间中的X轴)。 可以通过将P2-P1
(即, P2
的局部偏移相对于P1
)转换为球面坐标来计算这两个角度。 首先以俯仰角围绕X旋转物体,然后绕Y偏航。
像这样的东西会这样做(伪代码):
Matrix getTransformation(Point P1, Point P2) {
float length = distance(P1, P2);
Point direction = normalize(P2 - P1);
float pitch = acos(direction.y);
float yaw = atan2(direction.z, direction.x);
return translate(P1) * scaleY(length) * rotateX(pitch) * rotateY(yaw);
}
调用气缸A的轴。 第二次旋转(大约X )不能改变A和X之间的角度,所以我们必须在第一次旋转(大约Z )时获得该角度。
调用目标矢量(两点之间的矢量) B 。 拿-acos(B X / B Y ),这是第一次旋转的角度。
再次取B ,忽略X分量,并查看其在(Y,Z)平面中的投影。 取acos(B Z / B Y ),这就是第二次旋转的角度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.