拖动3D控制杆(基于方向和视角)

时间:2016-06-28 04:54:31

标签: c++ algorithm math 3d unreal-engine4

在我的项目(C ++ / UE4)中,我有一个伸出地板的杠杆网。在此控制杆上按住鼠标左键并移动鼠标即可启动拖动操作。此拖动操作负责计算2D delta鼠标移动,并利用此数据旋转局部空间* 中的杠杆 *,这只能在单个轴上旋转(负数或正数,但仍然只有一轴)。

但是,如果不是在杠杆前面,我实际上是在它背后呢?如果我在其中一方面怎么办?如果杠杆实际上是从墙壁而不是地板上伸出怎么办?...如何使鼠标移动实际上使杠杆适合于从其观察的角度旋转,无论杠杆的方向如何? / p>

进一步解释自己...
这是一个场景列表,以及我希望鼠标如何控制它们:

当杠杆位于FLOOR上并且你处于FRONT之前时:

  • 如果向上移动鼠标(-Y),它应该远离相机旋转
  • 如果您将鼠标向下移动(+ Y),它应朝向相机旋转

当杠杆位于FLOOR上并且你背后的时候:

  • 如果向上移动鼠标(-Y),它应该远离相机旋转 (当你在它面前时,这是与世界空间相反的方向)
  • 如果将鼠标向下移动(+ Y),它应朝向相机旋转 (当你在它面前时,这是与世界空间相反的方向)

当地板上的控制杆位于地板上时,你就是它:

  • 如果您将鼠标左移(-X),它应旋转到相机的左侧 (当你在另一边时,这是相反的方向)
  • 如果您将鼠标移动到右侧(+ X),它应该旋转到相机的右侧 (当你在另一边时,这是相反的方向)

当杠杆位于WALL上并且你处于它前面时:

  • 如果向上移动鼠标,它应向上旋转(朝向天空)
  • 如果您将鼠标向下移动,它应该向下旋转(朝向地板)

当杠杆位于WALL上并且你是BESIDE时:

  • 当它在墙上而你就在它前面时

请注意,如果它有帮助,UE4确实具有内置的2D / 3D矢量数学函数,以及向3D世界或2D屏幕投影和取消坐标的简便方法。因此,我总是知道鼠标位置的确切世界空间和屏幕空间坐标,杠杆的枢轴(基座)位置,杠杆的手柄(顶部)位置,以及鼠标的数量(delta)已移动每一帧。

2 个答案:

答案 0 :(得分:1)

获取控制杆的枢轴(其周围的点旋转),并将其投影到屏幕坐标。然后,当您第一次单击时,存储单击的坐标。

现在,当您需要知道旋转的方向时,您可以计算矢量旋转到第一次单击之间的点积和矢量枢轴到当前位置(您应该在点积之前对矢量进行标准化)。这为您提供了鼠标移动的cos(角度),您可以使用它(使用arccos(值)获得角度)以在3d中移动控制杆。由于屏幕上的角度与投影角度不同,所以会有点不稳定,但这种方式控制起来更容易(如果你将鼠标移动90度,即使它们不在,也会移动90度。 ; t正确对齐)。玩设置,看看哪种方式最适合您的项目。

另一种方法是这样做:当您第一次单击时,您可以在3d空间中存储控制杆末端的点(甚至更好地点击控制杆上的点)。您可以使用相机投影平面在3d中移动点(您可以使用相机向上矢量,使其与摄像机视图方向正交后,然后使用视图方向交叉向量来获得正确的方向)。您将鼠标增量运动应用于该点,然后将其投影到旋转平面并移动控制杆以将该点与投影点对齐(数学类似于上面的数学,只需使用3d点而不是屏幕投影)

注意:如果相机非常靠近旋转平面,这不能很好地工作,因为如果操纵杆向前或向后移动,它并不总是很清楚。

我不是unreal-engine4的专家(只是自学),但所有这些都是基本的矢量数学,应该得到很好的支持。查看维基百科上的点积和交叉积,因为它们对这些技巧非常有用。

答案 1 :(得分:0)

这是一种方法:

  1. 当用户单击操纵杆时,假设存在一个穿过操纵杆枢轴的平面,该平面的法线与从摄影机到枢轴的方向相同。.Calculate the intersection point光标的光线还有那架飞机。

    FVector rayOrigin;
    FVector rayDirection;
    FVector cameraPosition;
    FVector leverPivotPosition;
    
    FVector planeNormal = (leverPivotPosition-cameraPosition).GetSafeNormal(0.0001f);
    
    float t = ((leverPivotPosition - rayOrigin) | planeNormal) / (planeNormal | rayDirection);
    
    FVector planeHitPosition = rayOrigin + rayDirection * t;
    
  2. 将其标量投影到杠杆的本地上/下轴上。假设它是本地上/下轴:

    FVector leverLocalUpDirectionNormalized;
    
    float scalarPosition = planeHitPosition | leverLocalUpDirectionNormalized;
    
  3. 然后,在按住杆的每个其他框架中,为该框架计算新的scalarPosition。随着scalarPosition在两帧之间的增大,操纵杆应旋转,使其朝操纵杆的上侧移动。在框架之间减小时,操纵杆应朝操纵杆的下方旋转。