【问题标题】:How to randomly find one of the vectors from point P tangent to a sphere如何随机找到从点P切线到球体的向量之一
【发布时间】:2020-11-21 16:09:19
【问题描述】:

我想随机选择一个起源于点 P 的向量,这样在该向量旁边形成的线与某个球体的表面相切。为此,我需要在球体上形成一个圆的所有点 S 的集合,使得线 SP 在点 S 处与球体相切。然后,给定此信息,我可以选择一个点 S',并创建一个从点P到点S'的方向向量。

我想在 Unity 中执行此操作。我对如何创建向量本身没有太多偏好,只要它可以随机化并指向上述圆圈上的一个点。我相信一个理想的解决方案会考虑一个角度θ ∈ [0, 2π],它可以随机给出一个从圆(不是球体)原点到相关S'点的向量。

我很欣赏C# 中的解决方案,但我对其他语言也很满意。请注意,虽然数学解决方案值得赞赏,但我特别在寻找实现细节,因为我对 Unity 引擎、它们的坐标系和矢量运算还不是很熟悉。

下面的可视化:

【问题讨论】:

标签: c# unity3d math


【解决方案1】:

Unity中的解决方案如下:

  1. 计算圆的中心点
  2. 计算圆的半径
  3. 使用 3D 坐标中随机选择的点和点 P 创建投影
  4. 使用中心点和半径定位点,从而找到 S',使得 PS' 与球体相切
using UnityEngine;

public class Script : MonoBehaviour
{
    private readonly float _accuracy = 0.1f;
    private readonly int _vectorsCount = 1000;
    private readonly Vector3 _point = new Vector3(600, 600, 600);
    private readonly float _sphereRadius = 500f;

    private void Start()
    {
        // This value will be used to calculate both the circle coordinates and its radius.
        var quadraticSum = Mathf.Pow(_point.x, 2) + Mathf.Pow(_point.y, 2) + Mathf.Pow(_point.z, 2);

        // Find out coordinates of the circle created by the intersection of the plane with the sphere
        Vector3 circleCenter;
        circleCenter.x = _point.x * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
        circleCenter.y = _point.y * Mathf.Pow(_sphereRadius, 2) / quadraticSum;
        circleCenter.z = _point.z * Mathf.Pow(_sphereRadius, 2) / quadraticSum;

        // Find out radius of the above circle
        var circleRadius = _sphereRadius * Mathf.Sqrt(quadraticSum - Mathf.Pow(_sphereRadius, 2)) /
                           Mathf.Sqrt(quadraticSum);

        /*
         * At this point, we can start drawing - let's draw:
         *
         *   - the point using red colour
         *   - the sphere using blue colour
         *   - the circle using green colour
         *
         * Below assumes center of the sphere is at (0, 0, 0)
         */
        Debug.DrawLine(Vector3.zero, _point, Color.red, 1000);
        DrawSphere();
        DrawCircle(circleCenter, circleRadius);
    }

    private void DrawSphere()
    {
        for (var theta = -Mathf.PI; theta < Mathf.PI; theta += _accuracy)
        {
            for (var phi = -Mathf.PI; phi < Mathf.PI; phi += _accuracy)
            {
                var ray = new Vector3(
                    _sphereRadius * Mathf.Sin(theta) * Mathf.Cos(phi),
                    _sphereRadius * Mathf.Sin(theta) * Mathf.Sin(phi),
                    _sphereRadius * Mathf.Cos(theta)
                );
                Debug.DrawLine(Vector3.zero, ray, Color.blue, 1000);
            }
        }
    }

    private void DrawCircle(Vector3 center, float radius)
    {
        for (int i = 0; i < _vectorsCount; i++)
        {
            // Since I wanted random vectors, I am repeatedly drawing a random vector on the circle
            var tangentPoint = Vector3.ProjectOnPlane(Random.insideUnitSphere, _point).normalized * radius + center;
            Debug.DrawLine(Vector3.zero, tangentPoint, Color.green, 1000);
            //Debug.DrawLine(_point, tangentPoint, Color.cyan, 1000);
        }
    }
}

查看屏幕截图以进行可视化:

这是一个与球体和圆画完后画红线的角度,可以看到球体的中心:

【讨论】:

    猜你喜欢
    • 2020-08-02
    • 1970-01-01
    • 2018-10-31
    • 2011-04-08
    • 2019-08-23
    • 2011-07-28
    • 2019-06-13
    • 2016-03-19
    • 1970-01-01
    相关资源
    最近更新 更多