Как найти случайный вектор, ортогональный заданному вектору

У меня есть вектор с 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;
    }

person Oro Portaluri    schedule 01.04.2019    source источник
comment
stackoverflow.com/questions/11132681/ дает вам возможность найти ортогональные векторы - просто найдите 2 и используйте их случайные линейные комбинации.   -  person Alexei Levenkov    schedule 02.04.2019
comment
Представьте себе ортогональную плоскость, перпендикулярную точке на векторе. Итак, сначала вам нужна точка на исходном векторе. Итак, первый шаг - получить случайный X (от нуля до бесконечности), а затем решить для Y и Z на исходном векторе. Затем вы можете получить второй вектор, ортогональный первому. Второй вектор - это действительно любой вектор на плоскости, перпендикулярный первому вектору в точке первого вектора. Таким образом, вы действительно имеете дело с квадратом бесконечности. количество точек на исходном векторе. И затем Бесконечное количество векторов на плоскости, перпендикулярной 1-му вектору в точке.   -  person jdweng    schedule 02.04.2019


Ответы (1)


Для этого есть несколько способов. Я предоставлю два. Первый - однострочный, который использует кватернионы для генерации случайного вектора, а затем его вращения на место:

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, а вторая функция будет распространять ошибку и сама возвращать нулевой вектор.
person VPellen    schedule 02.04.2019
comment
Большое спасибо! Ты действительно мне очень помог - person Oro Portaluri; 02.04.2019