【问题标题】:Rotate a 3D- Point around another one围绕另一个旋转 3D 点
【发布时间】:2022-04-17 19:05:37
【问题描述】:

我的程序中有一个函数可以将点 (x_p, y_p, z_p) 围绕另一点 (x_m, y_m, z_m) 旋转角度 w_nxw_ny

新坐标存储在全局变量x_ny_nz_n 中。围绕y-axis 旋转(因此更改w_nx 的值 - 以便y - 值不会受到损害)工作正常,但只要我围绕x-z- 轴旋转(更改w_ny 的值)坐标不再准确。我评论了我认为是我的错在的那一行,但我无法弄清楚该代码有什么问题。

void rotate(float x_m, float y_m, float z_m, float x_p, float y_p, float z_p, float w_nx ,float w_ny)
    {
        float z_b = z_p - z_m;
        float x_b = x_p - x_m;
        float y_b = y_p - y_m;
        float length_ = sqrt((z_b*z_b)+(x_b*x_b)+(y_b*y_b));
        float w_bx = asin(z_b/sqrt((x_b*x_b)+(z_b*z_b))) + w_nx;
        float w_by = asin(x_b/sqrt((x_b*x_b)+(y_b*y_b))) + w_ny; //<- there must be that fault
        x_n = cos(w_bx)*sin(w_by)*length_+x_m;
        z_n = sin(w_bx)*sin(w_by)*length_+z_m;
        y_n = cos(w_by)*length_+y_m;
    }

【问题讨论】:

  • 如果您使用opengl,我确信图形库将包含您可以使用的矩阵和向量植入。通过矩阵旋转一个点将简化您的算法。
  • @ahenderson 您的意思是“实施”吗? ;)
  • 如果你还不熟悉这个术语,你应该阅读“云台锁”。我无法立即判断您的代码是否会受到影响,但是当您使用“欧拉角”进行这种旋转时,这是一个常见的缺陷。
  • 我尝试使用glrotatef,但它只旋转绘图,而不是顶点的坐标,我需要旋转坐标以检查碰撞!

标签: c++ math opengl trigonometry


【解决方案1】:

代码几乎做了什么:

  • 计算差分向量
  • 将矢量转换为spherical coordinates
  • 将 w_nx 和 wn_y 添加到倾角和方位角(有关术语,请参见链接)
  • 将修改后的球坐标转换回笛卡尔坐标

有两个问题:

  • 转换不正确,您所做的计算是针对两个倾角向量(一个沿 x 轴,另一个沿 y 轴)
  • 即使计算正确,球坐标中的变换也不等同于绕两个轴旋转

因此,在这种情况下,使用矩阵和向量数学会有所帮助:

b = p - m
b = RotationMatrixAroundX(wn_x) * b
b = RotationMatrixAroundY(wn_y) * b
n = m + b

basic rotation matrices.

【讨论】:

    【解决方案2】:

    尝试使用向量数学。决定你旋转的顺序,首先是x,然后可能是y

    如果你沿着z-axis[z' = z]旋转

    x' = x*cos a - y*sin a;
    y' = x*sin a + y*cos a;  
    

    y-axis 重复相同:[y'' = y']

    x'' = x'*cos b - z' * sin b;
    z'' = x'*sin b + z' * cos b;  
    

    再次沿x-axis旋转:[x''' = x'']

    y''' = y'' * cos c - z'' * sin c
    z''' = y'' * sin c + z'' * cos c
    

    最后是围绕某个特定“点”旋转的问题:

    首先,从坐标中减去点,然后应用旋转,最后将点添加回结果。

    据我所知,这个问题与“万向节锁”密切相关。角度 w_ny 不能相对于固定的 xyz 坐标系测量,而是相对于通过应用角度 w_nx 旋转的坐标系来测量。

    作为kakTuZ observed,您的代码将点转换为球坐标。这本身并没有什么问题——有了经度和纬度,人们就可以到达地球上的所有地方。如果有人不关心地球的赤道平面相对于它围绕太阳的轨迹倾斜,我没关系。

    不沿第一个w_ny旋转下一个参考轴的结果是赤道上相距1公里的两个点在两极和纬度90度处彼此靠近,他们接触。尽管表面上的目的是让它们在旋转的地方保持 1 公里的距离。

    【讨论】:

    • 为什么要使用 3 个角度? 2 就够了,我从哪里得到y''
    • @AndiFaust 缺少z'=zy''=y'x'''=x''。这三个计算是与“旋转矩阵”的矩阵乘法。
    • 如果你沿 y 轴旋转,y 不会改变等等。
    • 一切看起来都很好,但到目前为止我已经成功了 - 谁能告诉我 my 代码的错误在哪里?请!
    • @AkiSuihkonen 我不确定,但我认为这个解决方案是错误的。您必须更正以下行:z'' = z'*sin b + x' * cos b; -> z'' = x'*sin b + z' * cos b; z''' = z'' * sin c + y'' * cos c -> z''' = y'' * sin c + z'' * cos c。这有意义吗?
    【解决方案3】:

    如果您想转换坐标系而不是仅转换点,则需要 3 个角度。但你是对的 - 对于转换点 2 个角度就足够了。详情请咨询Wikipedia ...

    但是当你使用 opengl 时,你真的应该使用像 glRotatef 这样的 opengl 函数。这些函数将在 GPU 上计算 - 而不是作为您的函数在 CPU 上计算。文档是here

    【讨论】:

    • 我尝试使用glrotatef,但它只旋转绘图,而不是坐标,我需要旋转坐标以检查碰撞
    • 哦,你想做人工串通检查……我学习的时候实现了一个,它很痛苦而且很慢。也许您应该考虑使用physic engine
    【解决方案4】:

    正如许多其他人所说,您应该使用 glRotatef 旋转它以进行渲染。对于碰撞处理,您可以通过在其渲染点将其位置向量乘以堆栈顶部的 OpenGL ModelView 矩阵来获得其世界空间位置。使用 glGetFloatv 获取该矩阵,然后将其与您自己的向量矩阵乘法函数相乘,或者使用您可以轻松在线获得的众多函数之一。

    但是,那会很痛苦!相反,请考虑使用 GL 反馈缓冲区。此缓冲区将仅存储绘制图元的点,而不是实际绘制图元,然后您可以从那里访问它们。
    This 是一个很好的起点。

    【讨论】:

      猜你喜欢
      • 2021-10-28
      • 2018-02-17
      • 1970-01-01
      • 2012-11-21
      • 2014-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多