【问题标题】:How can I find the closest vector3 to a given target vector among all vectors orthogonal to a given input vector3?如何在与给定输入向量 3 正交的所有向量中找到最接近给定目标向量的向量 3?
【发布时间】:2019-08-29 06:23:59
【问题描述】:

假设我有两个幅值非零的输入向量:

Vector3 t;
Vector3 o;

我需要找到归一化向量v,以便在与o 正交的所有归一化向量中,v 是最接近这个t“目标”向量的向量。我还需要知道to 是否共线,在这种情况下不存在这样的单个v

这种关系的说明:

举一个具体的例子,假设我有一个游戏,玩家偶尔会在环境的表面上看到某个类似指南针的物体。玩家必须将指南针上的指针指向随机放置在游戏世界某处的图片对象。当玩家选择针的位置时,我需要知道玩家的选择距离对象的“真实”方向有多远。

罗盘指针固定绕轴旋转,世界方向为o(也许这是罗盘的transform.forward),图中游戏对象的方向为t

to不正交时,罗盘指针将无法直接指向t,所以我想知道:如何才能得到最接近的罗盘指针方向可以指向,也就是v这样,我可以测量这个目标方向和玩家选择的方向之间的角度。而且,当这个角度低于某个阈值时,玩家就成功了。

【问题讨论】:

  • 这听起来更适合Maths,因为实际实现似乎非常次要
  • @derHugo As far as I can tell,关于如何实施解决方案的问题(即使解决方案是基于数学的)都是主题。
  • 好吧,链接的问题被强烈反对,并且过于宽泛;)老实说,如果你还没有回答我会建议移动它,因为它主要是关于理解它背后的数学......还要注意other answer .. Unity 中的实现非常简单,因为这些方法的调用方式与解决方案背后的数学结构完全一样。这似乎更像是一个关于叉积如何工作的问题,我会说这是一个纯数学问题。

标签: c# unity3d math vector


【解决方案1】:

您可以使用向量叉积来解决这个问题。请注意,Vector3.Cross 的参数顺序很重要——参数顺序不一致会产生意想不到的结果。

  1. to 的叉积。

    Vector3 x = Vector3.Cross(t, o);
    
  2. 如果ot 共线,则x 将等于Vector3.zero

    if (x == Vector3.zero) 
    {
        // Handle colinear situation
    }
    
  3. 否则,x 将是与ot 正交的向量,因此也与v 正交:

    else
    {
    
  4. 现在我们有两个与v 正交的向量(即ox),我们可以做另一个叉积来找到与v 共线的向量。如果与我们用来计算x 的叉积相比,我们注意第二个叉积的顺序,那么第二个叉积的输出也将指向与v 相同的方向。剩下的就是对其进行规范化:

        Vector3 v = Vector3.Cross(o, x).normalized;
    
        // Use v
    }
    

总共:

Vector3 x = Vector3.Cross(t, o);

if (x == Vector3.zero) 
{
    // Handle colinear situation
}
else
{
    Vector3 v = Vector3.Cross(o, x).normalized;

    // Use v
}

【讨论】:

    【解决方案2】:

    让我说一个简单的方法来解决它。

    o 正交并共享相同起点的向量,并且为简单起见,具有与t 相同长度的向量填充o 起点处的正交圆。假设你找到了一个,你可以将它围绕o 旋转某个角度,它仍然是正交的。

    所以现在你有向量v 并且任务是寻找旋转角度。找到旋转角度后你自己就有答案了

    根据旋转角度写出vt 之间的距离等式。最小化这个距离——无论是数值还是解析求导并将它们分配给 0 都会为您提供旋转角度和最终 v

    您应该期望两个角度作为输出 - 一个用于具有最小距离的矢量,一个用于具有最大距离的矢量。简单的检查应该找出哪个是最小值

    【讨论】:

      【解决方案3】:

      使用Vector3.OrthoNormalize 是解决这个问题的一种方法,它可能比微积分或多个叉积更易于阅读。

      public static void OrthoNormalize(ref Vector3 normal, ref Vector3 tangent); 说明

      使向量标准化并相互正交。

      规范化normal。规范化tangent 并确保它与法线正交(即它们之间的角度为 90 度)。

      1. 通过查看 ot 的叉积是否为 Vector3.zero 来检查它们是否共线:

        if (Vector3.Cross(o,t) == Vector3.zero)
        {
            // Handle colinear situation
        }
        else 
        {
        
      2. 否则,复制ot,只修改副本:

            Vector3 oCopy = o;
            Vector3 tCopy = t;
        
      3. 使用Vector3.OrthoNormalize使用副本,t的副本为tangent

            Vector3.OrthoNormalize(ref oCopy, ref tCopy);
        
            Vector3 v = tCopy; // unnecessary; just included to have a variable named v
            // Use v
        }
        

      总共:

      if (Vector3.Cross(o,t) == Vector3.zero)
      {
          // Handle colinear situation
      }
      else 
      {
          Vector3 oCopy = o;
          Vector3 tCopy = t;
      
          Vector3.OrthoNormalize(ref oCopy, ref tCopy);
      
          Vector3 v = tCopy; // unnecessary; just included to have a variable named v
          // Use v
      }
      

      【讨论】:

        猜你喜欢
        • 2012-05-25
        • 2019-08-23
        • 2016-02-13
        • 2023-03-12
        • 1970-01-01
        • 2015-01-10
        • 1970-01-01
        • 1970-01-01
        • 2011-02-22
        相关资源
        最近更新 更多