简体   繁体   English

围绕另一个旋转3D点

[英]Rotate a 3D- Point around another one

I have a function in my program which rotates a point (x_p, y_p, z_p) around another point (x_m, y_m, z_m) by the angles w_nx & w_ny. 我的程序中有一个函数,可以将一个点(x_p,y_p,z_p)绕另一个点(x_m,y_m,z_m)旋转角度w_nx和w_ny。 The new coordinates are stored in global variables x_n, y_n, and z_n. 新坐标存储在全局变量x_n,y_n和z_n中。 Rotation around the y-axis (so changing value of w_nx - so that the y - values are not harmed) is working correctly, but as soon as I do a rotation around the x- or z- axis (changing the value of w_ny) the coordinates aren't accurate any more. 绕y轴旋转(因此更改w_nx的值-以使y-值不受损害)可以正常工作,但是当我绕x轴或z轴旋转时(更改w_ny的值)坐标不再精确。 I commented on the line I think my fault is in, but I can't figure out what's wrong with that code. 我在我认为我的错所在的那行上发表了评论,但我无法弄清楚该代码出了什么问题。

Can anyone help me? 谁能帮我?

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;
    }

What the code almost does: 该代码几乎可以做什么:

  • compute difference vector 计算差异向量
  • convert vector into spherical coordinates 将向量转换为球坐标
  • add w_nx and wn_y to the inclination and azimuth angle (see link for terminology) 将w_nx和wn_y添加到倾斜度和方位角(请参阅术语链接)
  • convert modified spherical coordinates back into Cartesian coordinates 将修改后的球坐标转换回笛卡尔坐标

There are two problems: 有两个问题:

  • the conversion is not correct, the computation you do is for two inclination vectors (one along the x axis, the other along the y axis) 转换不正确,您的计算是针对两个倾斜向量(一个沿x轴,另一个沿y轴)
  • even if computation were correct, transformation in spherical coordinates is not the same as rotating around two axis 即使计算正确,球形坐标的变换也不同于绕两轴旋转

Therefore in this case using matrix and vector math will help: 因此,在这种情况下,使用矩阵和向量数学将有所帮助:

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

basic rotation matrices . 基本旋转矩阵

Try to use vector math. 尝试使用向量数学。 decide in which order you rotate, first along x, then along y perhaps. 确定旋转的顺序,首先沿x,然后沿y。

If you rotate along z, [z' = z] 如果沿z旋转,则[z'= z]

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

The same repeated for y-axis: [y'' = y'] y轴重复相同:[y''= y']

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

Again rotating along x-axis: [x''' = x''] 再次沿x轴旋转:[x'''= x'']

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

And finally the question of rotating around some specific "point": 最后是围绕某个特定“点”旋转的问题:

First subtract the point from the coordinates, then apply the rotations and finally add the point back to the result. 首先从坐标中减去该点,然后应用旋转,最后将该点加回到结果中。

The problem, as far as I see, is a close relative to "gimbal lock". 据我所知,这个问题与“万能锁”密切相关。 The angle w_ny can't be measured relative to the fixed xyz -coordinate system, but to the coordinate system that is rotated by applying the angle w_nx. 不能相对于固定的xyz坐标系测量角度w_ny,而是相对于通过应用角度w_nx旋转的坐标系。

As kakTuZ observed, your code converts point to spherical coordinates. 正如kakTuZ所观察到的,您的代码将点转换为球面坐标。 There's nothing inherently wrong with that -- with longitude and latitude one can reach all the places in Earth. 这样做本质上没有错-经度和纬度可以到达地球上的所有地方。 And if one doesn't care about tilting the Earth equatorial plane relative to it's trajectory around the Sun, it's ok with me. 如果不关心地球赤道平面相对于其绕太阳轨道的倾斜,我也可以。

The result of not rotating the next reference axis along the first w_ny is that two points that are 1 km a part of each other at equator, move closer each other at the poles and at latitude of 90 degrees, they touch. 不沿第一个w_ny旋转下一个参考轴的结果是,在赤道处彼此相距1 km的两个点在极点处彼此靠近并以90度的纬度移动,它们接触。 Even though the apparent purpose is to keep them 1 km apart where ever they are rotated. 即使明显的目的是使它们在旋转位置之间保持1公里的距离。

if you want to transform coordinate systems rather than only points you need 3 angles. 如果要变换坐标系而不是仅变换点,则需要3个角度。 But you are right - for transforming points 2 angles are enough. 但是您是对的-对于变换点,两个角度就足够了。 For details ask Wikipedia ... 有关详细信息,请查阅Wikipedia ...

But when you work with opengl you really should use opengl functions like glRotatef . 但是,当您使用opengl时,您确实应该使用诸如glRotatef类的opengl glRotatef These functions will be calculated on the GPU - not on the CPU as your function. 这些函数将在GPU上计算-而不是在CPU上计算。 The doc is here . 文档在这里

Like many others have said, you should use glRotatef to rotate it for rendering. 就像许多其他人所说的那样,您应该使用glRotatef旋转它进行渲染。 For collision handling, you can obtain its world-space position by multiplying its position vector by the OpenGL ModelView matrix on top of the stack at the point of its rendering. 对于碰撞处理,您可以通过将其位置向量乘以堆栈顶部渲染层上的OpenGL ModelView矩阵来获得其世界空间位置。 Obtain that matrix with glGetFloatv, and then multiply it with either your own vector-matrix multiplication function, or use one of the many ones you can obtain easily online. 使用glGetFloatv获取该矩阵,然后将其与您自己的矢量矩阵乘法函数相乘,或者使用可以轻松在线获得的众多矩阵之一。

But, that would be a pain! 但是,那会很痛苦! Instead, look into using the GL feedback buffer. 相反,应考虑使用GL反馈缓冲区。 This buffer will simply store the points where the primitive would have been drawn instead of actually drawing the primitive, and then you can access them from there. 该缓冲区将仅存储将要绘制图元的点,而不是实际绘制图元,然后您可以从那里访问它们。
This is a good starting point. 是一个很好的起点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM