2011-08-02

Mapowanie tekstury na sferę

Rysunek:


  
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
    
    
      
      
    
    
      
      
    
    
    
    P
    O
    U
    F
    R
    A
    B
    φ
    ϴ
    
    
  
Wektory $\mathbf{\hat U}$ (góra), $\mathbf{\hat F}$ (wprzód), $\mathbf{\hat 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 $\mathbf{\theta}$, v zależy od kąta $\mathbf{\varphi}$, $\mathbf{u\in \left < 0,1 \right >}$, $\mathbf{v\in \left < 0,1 \right >}$, $\mathbf{0\leqslant u+v\leqslant 1}$.

Poniżej podane wzory znacząco się upraszczają jeśli wektory $\mathbf{\hat U}$, $\mathbf{\hat F}$, $\mathbf{\hat 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ść:

$\hat N = \widehat{OP}$
Wyznaczenie wartości $\mathbf{\varphi}$:

$\cos \varphi = \hat U \cdot \hat N$

$\varphi = arccos \left ( \hat U \cdot \hat N \right )$
Wyznaczenie wartości $\mathbf{\theta}$:

$\vec A = \hat U \times \hat N$

$\hat B = \widehat{\vec A \times \hat U}$

$\cos \theta = \hat N \cdot \hat B$

$\theta = arccos \left ( \hat N \cdot \hat B \right )$
Mając wyznaczone oba kąty trzeba je zmapować na (u,v).

Chcemy by v zależał kąta $\mathbf{\varphi}$. Zauważmy że wartości funkcji arccos zmieniają się w zakresie $\mathbf{\left < 0, \pi \right >}$. Dla ujemnych wartości $\mathbf{\varphi}$ wartość arccos nie zmienia się co do znaku. Tak więc:

$v = \displaystyle\frac{\varphi}{\pi}$
W przypadku mapowania v znak kąta ma znaczenie. Chcemy by v zmieniało się w granicach od zera do jeden dla $\mathbf{\theta}$ zmieniającej się od 0 do $2\pi$. Ponieważ arccos zmienia się w zakresie $\left < 0, \pi \right >$ musimy rozpoznać czy punkt P leży z tyłu, czy z przodu sfery. W tym celu badamy znak $\mathbf{\cos \alpha = \hat F \cdot \hat B}$. Jest on równy kosinusowi kąta między tymi dwoma wektorami. Jeśli $\cos \alpha > 0$ to $\displaystyle-\frac{\pi}{2}<\alpha<\displaystyle\frac{\pi}{2}$. Czyli punkt P znajduje się z tyłu sfery. Dla punktów z tyłu sfery współrzędną u liczymy tak:

$v = \displaystyle\frac{\theta}{2\pi}$
Z przodu:

$v = 1 - \displaystyle\frac{\theta}{2\pi}$
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);
}

Dodanie skalowanie obiektów

Dodanie skalowanie umożliwi nam skalowanie obiektów, dzięki czemu będziemy w stanie przeskalować element lub grupę elementów sceny bez modyfikacji ich współrzędnych i parametrów. Dzięki skalowaniu będziemy też mogli zrobić z sfery elipsoidę.

Dodanie skalowania wymusi zmiany na większości już napisanego kodu. Większość parametrów intersekcji i samego promienia przed wykorzystaniem w kodzie obiektów sceny będzie musiała zostać sprowadzona do lokalnego układu współrzędnych.

Dzięki temu kod w wielu miejscach będzie można uprościć gdyż obiekt w lokalnym układzie współrzędnych będzie zorientowany wzdłuż wersorów układu współrzędnych, a jego środek będzie w środku układu współrzędnych.

Z dużym prawdopodobieństwem zmiany wprowadzone przy okazji dodawania skalowania powinny także pociągnąć pochylanie.

Współczynniki skalowania mogą być także ujemne.

Orientacja obiektu w przestrzeni - skalowanie

Po dodaniu skalowania do informacji orientującej obiekt w przestrzeni kod tworzący macierze transformacji świat-obiekt zmienia się z :
private void UpdateTransformationMatrices()
{
    m_local_to_world = Matrix4.CreateTranslation(Pos) *
        new Matrix4(Right, Up, Forward);
    m_world_to_local = m_local_to_world.Inverted;
}
na:
private void UpdateTransformationMatrices()
{
    m_local_to_world = Matrix4.CreateTranslation(Pos) * 
        new Matrix4(Right, Up, Forward) * Matrix4.CreateScale(Scale);
    m_world_to_local = m_local_to_world.Inverted;
}