簡體   English   中英

給定角度的 3D 球體上的隨機旋轉

[英]Random Rotation on a 3D sphere given an angle

這個問題介於計算機圖形、概率和編程之間,但由於我是用 C# 為 Unity 項目編寫代碼,因此我決定將其發布在這里。 不合適請見諒。

我需要解決這個問題:給定一個 3d 球體上某個位置的物體,並給定一個度數范圍,球體上的采樣點在給定范圍內均勻分布。

例如: 左圖:立方體代表球體的中心,綠色球體是起始位置。 我想在一定程度上均勻覆蓋圓的所有表面,例如圍繞綠色球體從 -90 到 90 度。 我的方法(右圖)不起作用,因為它對靠近起始位置的點進行了過采樣。

在此處輸入圖片說明

我的采樣器:


Vector3 getRandomEulerAngles(float min, float max)
{
    float degree = Random.Range(min, max);
    return degree * Vector3.Normalize(new Vector3(Random.Range(min, max), Random.Range(min, max), Random.Range(min, max)));
}

為了覆蓋球體的上半部分,我會調用getRandomEulerAngles(-90, 90)

任何的想法?

我們可以為此使用均勻球體采樣。 給定兩個隨機變量uv (均勻分布),我們可以計算球體(也是均勻分布)上的隨機點(p, q, r)

float azimuth = v * 2.0 * PI;
float cosDistFromZenith = 1.0 - u;
float sinDistFromZenith = sqrt(1.0 - cosDistFromZenith * cosDistFromZenith);
(p, q, r) = (cos(azimuth) * sinDistFromZenith, sin(azimuth) * sinDistFromZenith, cosDistFromZenith);

如果我們將我們的參考方向(您的物體位置)置於天頂位置,我們需要從[0, 1]采樣v以獲得圍繞物體的所有方向,而u[cos(minDistance), cos(maxDistance)] ,其中minDistancemaxDistance是您想要允許的對象的角度距離。 90°Pi/2距離會給你一個半球。 180°Pi距離將為您提供完整的球體。

現在我們可以在天頂位置對物體周圍的區域進行采樣,我們還需要考慮其他物體的位置。 讓物體位於(ox, oy, oz) ,這是一個單位向量,描述了從球心開始的方向。

然后我們建立一個局部坐標系:

rAxis = (ox, oy, oz)
pAxis = if |ox| < 0.9 : (1, 0, 0)
        else          : (0, 1, 0)
qAxis = normalize(cross(rAxis, pAxis))
pAxis = cross(qAxis, rAxis)

最后,我們可以得到球面上的隨機點 (x, y, z):

(x, y, z) = p * pAxis + q * qAxis + r * rAxis

嘗試這個:

public class Sphere : MonoBehaviour
{
    public float Radius = 10f;
    public float Angle = 90f;

    private void Start()
    {
        for (int i = 0; i < 10000; i++)
        {
            var randomPosition = GetRandomPosition(Angle, Radius);
            Debug.DrawLine(transform.position, randomPosition, Color.green, 100f);
        }
    }

    private Vector3 GetRandomPosition(float angle, float radius)
    {
        var rotationX = Quaternion.AngleAxis(Random.Range(-angle, angle), transform.right);
        var rotationZ = Quaternion.AngleAxis(Random.Range(-angle, angle), transform.forward);
        var position = rotationZ * rotationX * transform.up * radius + transform.position;

        return position;
    }
}

改編自 Nice Schertler,這是我正在使用的代碼


    Vector3 GetRandomAroundSphere(float angleA, float angleB, Vector3 aroundPosition)
    {
        Assert.IsTrue(angleA >= 0 && angleB >= 0 && angleA <= 180 && angleB <= 180, "Both angles should be[0, 180]");
        var v = Random.Range(0F, 1F);
        var a = Mathf.Cos(Mathf.Deg2Rad * angleA);
        var b = Mathf.Cos(Mathf.Deg2Rad * angleB);

        float azimuth = v * 2.0F * UnityEngine.Mathf.PI;
        float cosDistFromZenith = Random.Range(Mathf.Min(a, b), Mathf.Max(a, b));
        float sinDistFromZenith = UnityEngine.Mathf.Sqrt(1.0F - cosDistFromZenith * cosDistFromZenith);
        Vector3 pqr = new Vector3(UnityEngine.Mathf.Cos(azimuth) * sinDistFromZenith, UnityEngine.Mathf.Sin(azimuth) * sinDistFromZenith, cosDistFromZenith);
        Vector3 rAxis = aroundPosition; // Vector3.up when around zenith
        Vector3 pAxis = UnityEngine.Mathf.Abs(rAxis[0]) < 0.9 ? new Vector3(1F, 0F, 0F) : new Vector3(0F, 1F, 0F);
        Vector3 qAxis = Vector3.Normalize(Vector3.Cross(rAxis, pAxis));
        pAxis = Vector3.Cross(qAxis, rAxis);
        Vector3 position = pqr[0] * pAxis + pqr[1] * qAxis + pqr[2] * rAxis;
        return position;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM