如何找到与给定向量正交的随机向量

How to find a randomic Vector orthogonal to a given Vector

我有一个包含 3 个分量(X、Y、Z)的向量,我想找到一个与给定分量正交的向量。由于与任何矢量正交的矢量都是无限的,我只需要一个随机的。

我已经尝试使用点积公式的方程式,因为两个正交向量之间的点积始终为 0,并且我设法编写了一些代码,仅当给定的向量与轴对齐时才有效,但这可能是因为向量的随机分量是 X 和 Y。我真的无法理解这个问题。

我在 Unity3D 引擎上编写了我的代码,以便能够轻松地将其可视化:

Vector3 GenerateOrthogonal(Vector3 normal)
    {
        float x = Random.Range(1f, -1f);
        float y = Random.Range(1f, -1f);

        float total = normal.x * x + normal.y * y;
        float z = -total / -normal.z;

        return new Vector3(x, y, z).normalized;
    }

有几种方法可以做到这一点。我会提供两个。第一个是使用四元数生成随机向量然后将其旋转到位的单行代码:

Vector3 RandomTangent(Vector3 vector) {
    return Quaternion.FromToRotation(Vector3.forward, vector) * (Quaternion.AngleAxis(Random.Range(0f, 360f), Vector3.forward) * Vector3.right);
}

第二个更长,数学更严谨,平台依赖性更小:

Vector3 RandomTangent(Vector3 vector) {
    var normal = vector.normalized;
    var tangent = Vector3.Cross(normal, new Vector3(-normal.z, normal.x, normal.y));
    var bitangent = Vector3.Cross(normal, tangent);
    var angle = Random.Range(-Mathf.PI, Mathf.PI);
    return tangent * Mathf.Sin(angle) + bitangent * Mathf.Cos(angle);
}

以下是关于它们的区别的一些注释:

  • 这两个函数都会生成具有均匀分布的随机垂直向量(或 "tangent")。
  • 您可以通过获取输入和输出之间的角度来衡量这些函数的准确性。虽然大多数时候它正好是 90,但有时会有非常小的偏差,主要是由于浮点舍入误差。
  • 虽然这两个函数都不会产生大错误,但第二个函数产生错误的频率要低得多。
  • 初步实验表明这些函数的性能非常接近,更快的函数可能因平台而异。第一个实际上 更快 在我的机器上用于标准 Windows 构建,这让我措手不及。
  • 如果您准备假设第二个函数的输入是归一化向量,则可以删除输入的显式归一化并获得性能提升。如果你这样做然后传递一个非归一化向量,你仍然会得到一个垂直向量作为结果,但它的长度和分布将不再可靠地均匀。
  • 在传递零向量的退化情况下,第一个函数将在 XY 平面上生成随机向量,而第二个函数将传播误差和 return 零向量本身。