Loading [MathJax]/jax/output/HTML-CSS/jax.js

2011-08-02

Mapowanie tekstury na sferę

Rysunek:


  
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
    
    
      
      
    
    
      
      
    
    
    
    P
    O
    U
    F
    R
    A
    B
    φ
    ϴ
    
    
  
Wektory ˆU (góra), ˆF (wprzód), ˆR (prawo) orientując sferę w przestrzeni. Zakładamy, że wektory te są znormalizowane. Mapowanie przeprowadzamy dla punktu P znajdującego się na sferze.

Do wyznaczenia jest para (u,v), gdzie u zależy od kąta θ, v zależy od kąta φ, u0,1, v0,1, 0u+v1.

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 θ:

A=ˆU׈N

ˆB=^A׈U

cosθ=ˆNˆB

θ=arccos(ˆNˆB)
Mając wyznaczone oba kąty trzeba je zmapować na (u,v).

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