Do wyznaczenia jest para (u,v), gdzie u zależy od kąta θ, v zależy od kąta φ, u∈⟨0,1⟩, v∈⟨0,1⟩, 0⩽u+v⩽1.
Poniżej podane wzory znacząco się upraszczają jeśli wektory ˆU, ˆF, ˆR są wersorami układu współrzędnych, a środek sfery to środek układu współrzędnych. Wtedy korzystamy z klasycznych wzorów na konwersję z układu kartezjańskiego na sferyczny.
Normalna (wektor znormalizowany) w punkcie P ma wartość:
ˆN=^OP
Wyznaczenie wartości φ:cosφ=ˆU⋅ˆN
φ=arccos(ˆU⋅ˆN)
Wyznaczenie wartości θ:φ=arccos(ˆU⋅ˆN)
→A=ˆU׈N
ˆB=^→A׈U
cosθ=ˆN⋅ˆB
θ=arccos(ˆN⋅ˆB)
Mając wyznaczone oba kąty trzeba je zmapować na (u,v). ˆB=^→A׈U
cosθ=ˆN⋅ˆB
θ=arccos(ˆN⋅ˆB)
Chcemy by v zależał kąta φ. Zauważmy że wartości funkcji arccos zmieniają się w zakresie ⟨0,π⟩. Dla ujemnych wartości φ wartość arccos nie zmienia się co do znaku. Tak więc:
v=φπ
W przypadku mapowania v znak kąta ma znaczenie. Chcemy by v zmieniało się w granicach od zera do jeden dla θ zmieniającej się od 0 do 2π. Ponieważ arccos zmienia się w zakresie ⟨0,π⟩ musimy rozpoznać czy punkt P leży z tyłu, czy z przodu sfery. W tym celu badamy znak cosα=ˆF⋅ˆB. Jest on równy kosinusowi kąta między tymi dwoma wektorami. Jeśli cosα>0 to −π2<α<π2. Czyli punkt P znajduje się z tyłu sfery. Dla punktów z tyłu sfery współrzędną u liczymy tak:v=θ2π
Z przodu:v=1−θ2π
Przykład implementacji w C#:public override Vector2 GetUV(Intersection a_intersection) { Vector3 normal = (a_intersection.Pos - Pos).Normalized; Vector3 B = Vector3.CrossProduct( Vector3.CrossProduct(Up, normal), Up).Normalized; double a = Forward * B; if (a < 0) { return new Vector2( 1 - (Math.Acos(Right * B) / (2 * Constants.PI)), Math.Acos(Up * normal) / Constants.PI); } else { return new Vector2( Math.Acos(Right * B) / (2 * Constants.PI), Math.Acos(Up * normal) / Constants.PI); } }W przypadku gdy punkt na sferze do lokalnego układu współrzędnych obliczenia znacząco się upraszczają:
public virtual Vector3 GetUVW(Intersection a_intersection) { return WorldToLocal * a_intersection.Pos; } public override Vector2 GetUV(Intersection a_intersection) { Vector3 uvw = a_intersection.UVW; double v = Math.Acos(uvw.Y / uvw.Length) / Constants.PI; double u1 = Math.Atan2(uvw.Z, uvw.X) / (2 * Constants.PI); if (uvw.Z > 0) return new Vector2(u1, v); else return new Vector2(1 + u1, v); }
Brak komentarzy:
Prześlij komentarz