C# 如何在与给定输入向量3正交的所有向量中找到与给定目标向量最近的向量3?

C# 如何在与给定输入向量3正交的所有向量中找到与给定目标向量最近的向量3?,c#,unity3d,math,vector,C#,Unity3d,Math,Vector,假设我有两个非零量级的输入向量: Vector3 t; Vector3 o; 我需要找到归一化向量v,这样在所有与o正交的归一化向量中,v是最接近t目标向量的向量。我还需要知道t和o是否共线,在这种情况下,不存在这样一个v 这种关系的说明: 作为一个具体的例子,假设我有一个游戏,玩家偶尔会在环境中的某个表面上看到一个类似指南针的物体。玩家必须将指南针上的指针指向游戏世界中随机放置的图片对象。当玩家选择针的位置时,我需要知道玩家的选择距离物体的真实方向有多远 指南针固定在绕着世界方向为o的轴旋转

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

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

这种关系的说明:

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

指南针固定在绕着世界方向为o的轴旋转——也许这是指南针的transform.forward,而图中游戏对象的方向是t


当t和o不正交时,指南针将无法直接指向t,因此我想知道:如何获得指南针可能指向的最近方向,即v?这样,我可以测量这个目标方向和球员选择的方向之间的角度。并且,当该角度低于某个阈值时,播放器成功。

您可以使用向量叉积来解决此问题。请注意,Vector3.Cross matters的参数顺序不一致会产生意外的结果

取t和o的叉积

如果o和t是共线的,x将等于向量3.0

否则,x将是与o和t正交的向量,因此也与v正交:

现在我们有了两个与v正交的向量,也就是o和x,我们可以做另一个叉积来找到一个与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
}
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
}

让我用简单的方法来解决它

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

现在你们有了向量v,寻找的是旋转角度。找到旋转角度后,你就得到了答案

根据旋转角度写出v和t之间距离的方程式。最小化这个距离——无论是数值上的,还是解析上的求导,并将它们指定为0,都将为您提供旋转角度和最终v


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

解决这个问题的一种方法可能比微积分或多个叉积更容易阅读

公共静态无效正交规范化ref Vector3法线,ref Vector3切线; 描述

使向量规格化并相互正交

正常化。规格化切线并确保其与法线正交,即两者之间的角度为90度

通过查看o和t的叉积是否为矢量3.0来检查它们是否共线:

否则,复制o和t以便仅修改副本:

    Vector3 oCopy = o;
    Vector3 tCopy = t;
使用Vector3.OrthoNormalize使用副本,t的副本作为切线:

总共:

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

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

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

这听起来更适合,因为实际实现似乎非常复杂secondary@derHugo,即使解决方案是基于数学的,询问如何实施该解决方案的问题也是基于主题的;老实说,如果你还没有回答的话,我会建议你把它移走,因为它主要是关于理解它背后的数学。。还要注意。。在Unity中的实现非常简单,因为方法的调用与解决方案背后的数学构造完全相同。这似乎更像是一个关于叉积如何工作的问题,我会说这是一个纯粹的数学问题。
    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
}
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
}