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

标签 c# unity3d vector trigonometry orthogonal

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

我已经尝试使用点积公式的等式,因为两个正交向量之间的点积始终为 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);
}

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

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

关于c# - 如何找到与给定向量正交的随机向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55464852/

相关文章:

c# - 在 BundleConfig.cs 中找不到 BundleCollection

c++ - 使用 Unity3D 作为带有 OpenGL 应用程序的 Win32 c++ 的 GUI

r - 将数据帧的每一列乘以向量的对应值

c# - 将多个 CSS 类添加到富文本编辑器 Sitecore 8

c# - 如何使用 C# 返回序列化为 JSON

c# - 在 Resharper ContextAction 中抑制 IProgressIndicator

android - “允许 [app name] 调用和管理电话”权限和 READ_PHONE_STATE

c# - 定义 iTween 路径时的恒速问题

c++ - 将 cv::Mat 转换为 vector<int>

image - 从另一个 SVG <path> 中剪出一个