2011-07-22

Mapowanie tesktury na płaszczyznę

Musimy ustalić współrzędne tekstury (u,v), gdzie $\mathbf{0<=u<=1}$, $\mathbf{0<=v<=1}$. Taką współrzędną łatwo później przeskalować na konkretną bitmapę lub wykorzystać w wyliczaniu tekstury proceduralnej.

Aby zorientować teksturę na płaszczyźnie potrzebujemy punktu na płaszczyźnie, który będzie początkiem układu współrzędnych i dwóch wektorów orientujących wokół tego punktu dwuwymiarowy układ współrzędnych leżący na płaszczyźnie.

Do zorientowania obiektu w 3D potrzebujemy jego pozycji i dwa wektory orientujące jego układ współrzędnych. Trzeci wektor możemy sobie wyliczyć z iloczynu wektorowego. Z punktu (przesunięcia) i 3 wektorów budujemy macierze transformacji świat-obiekt i obiekt-świat.

Mnożąc punkt należący do płaszczyzny przez macierz świat-obiekt sprowadzamy do układu współrzędnych obiektu. Zakładamy, że taki punkt ciągle leży na płaszczyźnie.

Jego współrzędne X i Z wyznaczą nam współrzędne tekstury (u,v).

Ostatni problem do rozwiązania to nieskończoność płaszczyzny, który wymusza na nas przeskalowanie współrzędnych tekstury do pożądanego przez nas wizualnego efektu.

Orientacja obiektu w przestrzeni

Każdy silnik czy to raytracingu czy renderingu umieszczając obiekty w układzie współrzędnych świata wykorzystuje informację o położeniu obiektu i jego orientacji.

Orientację wyznaczają trzy wektory, które wskazują w górę obiektu, w jego bok i naprzód (z reguł jednostkowe i wzajemnie prostopadłe). W tych wektorów i pozycji budujemy dwie macierze świat-obiekt i obiekt-świat, jedna jest odwrotnością drugiej.

Mnożąc punkt świata przez macierz świat-obiekt sprowadzamy go układu współrzędnych obiektu. Z reguły w takim układzie środek układu współrzędnych to środek obiektu.

Tworzenie macierzy transformacji:
private void UpdateTransformationMatrices()
{
    m_local_to_world = Matrix4.CreateTranslation(Pos) *
        new Matrix4(Right, Up, Forward);
    m_world_to_local = m_local_to_world.Inverted;
}
Zwróćmy uwagę, że przy transformacji świat-obiekt najpierw przesuwamy punkt, a następnie go obracamy. Przy transformacji odwrotnej obiekt-świat jest odwrotnie.

Często jest tak, że nasz obiekt zawiera w sobie inne, a one znowu inne, a każdy ma swoje macierze transformacji. Ostateczna macierz transformacji powstaje przez wymnożenie wszystkich składowych macierzy.

Mapowanie tekstury - informacje ogólne

Mając punkt uderzenia promienia w obiekt musimy ustalić współrzędne tekstury (u,v), gdzie $\mathbf{0<=u<=1}$, $\mathbf{0<=v<=1}$. Taką współrzędną łatwo później przeskalować na konkretną bitmapę lub wykorzystać w wyliczaniu tekstury proceduralnej.

2011-07-20

Intersekcja promienia z płaszczyzną

Równanie promienia w postaci parametrycznej wychodzącego z punktu P w kierunku $\mathbf{\vec d}$

$x = P + \vec{d}t$
Parametr t możemy potraktować jako czas. Jest ono identyczne z równaniem parametrycznym linii, nadajemy tylko innego znaczenia parametrom.

Równanie parametryczne płaszczyzny w postaci wektorowej:

$\vec n \cdot x + D = 0$
Z porównania:

$\vec n(P + \vec{d}t) + D = 0$
Stąd:

$t=\displaystyle-\frac{D + \vec{n}P}{\vec{n} \cdot \vec d}$
Jeśli $\mathbf{t<0}$ to przecięcie nastąpiło po przed miejscem wyjścia promienia. Traktując promień jako prostą takie t ma sens. Jeśli $\mathbf{t>=0}$ punkt przecięcia promienia z prostą istnieje.

Warunkiem istnienia punktu przecięcia jest to by płaszczyzn była nierównoległa do promienia, czyli $\mathbf{\vec n \cdot \vec d} \neq 0$.

Punkt przecięcia wyznaczamy podstawiając t do równania prostej.

Aby ustalić z której strony płaszczyzny nastąpiło uderzenie badamy znak wyrażenia $\mathbf{\vec{n} \cdot \vec d}$. Jeśli $\mathbf{\vec{n} \cdot \vec d}<0$ uderzenie nastąpiło z przodu płaszczyzny (z kierunku który wskazuje normalna płaszczyzny). Jeśli $\mathbf{\vec{n} \cdot \vec d}>0$ uderzenie nastąpiło z tyłu. Jeśli $\mathbf{\vec{n} \cdot \vec d}=0$ promień jest równoległy do płaszczyzny.

Przykład implementacji w C#:
public override Intersection GetIntersection(Ray a_ray)
{
    double denom = Normal * a_ray.Dir;

    if (OneSide)
    {
        if (denom > 0)
            return Scene.NoIntersection;
    }

    if (a_ray.PrevHit == this)
        return Scene.NoIntersection;

    if (!denom.IsZero())
    {
        double dist = ((Normal * a_ray.Start) - Distance) / (-denom);

        if (dist <= 0)
            return Scene.NoIntersection;
        else
        {
            bool backHit = (denom > 0);

            if (backHit && OneSide)
                return Scene.NoIntersection;
            else
            {
                return new Intersection()
                {
                    SceneObject = this,
                    SourceRay = a_ray,
                    Dist = dist,
                    Scene = Scene,
                    BackHit = backHit,
                    Pos = a_ray.HitPoint(dist)
                };
            }
        }
    }
    else
        return Scene.NoIntersection;
}

2011-07-19

Odległość punktu od płaszczyzny

Mamy dowolny punkt płaszczyzny $\mathbf{x_0}$, jej normalną $\mathbf{\vec n}$. Należy znaleźć odległość punktu $\mathbf{x}$ od płaszczyzny. Jest to odległość minimalna, czyli odległość pomiędzy punktem $\mathbf{x}$, a takim punktem płaszczyzny, że wektor wyznaczony przez te dwa punkty jest równoległy do normalnej płaszczyzny.

Odległość ta jest niczym innym jak długością rzutu wektora $\mathbf{\vec v = x_0 - x}$ na wektor normalny. Czyli:

$d=|(\vec v \cdot \vec n) \hat n|$
$d=|((x-x_0) \cdot \vec n) \hat n|$
Jeśli wektor $\mathbf{\vec n}$ jest znormalizowany to:

$d=\vec v \cdot \vec n$
$d=(x-x_0) \cdot \vec n$
W szczególności jeśli punkt $\mathbf{x=(0,0,0)}$ to otrzymujemy odległość płaszczyzny od początku układu współrzędnych ze znakiem minus.

Znak $\mathbf{d}$ wskazuje nam po której stronie płaszczyzny leży punkt $\mathbf{x_0}$.

Równanie płaszczyzny

Równanie płaszczyzny ma postać:

$\vec N \cdot (X - X_0)$
, gdzie $\mathbf{\vec N=[A,B,C]}$ to normalna płaszczyzny, $\mathbf{X=(x,y,z)}$ to dowolny punkt płaszczyzny, $\mathbf{X_0=[x_0,y_0,z_0]}$ to znany punkt płaszczyzny. Iloczyn skalarny dwóch wektorów wzajemnie do siebie prostopadłych równy jest zeru. Równianie to więc spełniają takie $\mathbf{x}$, które leżą na płaszczyźnie prostopadłej do $\mathbf{\vec N}$ i przechodzącej przez punkt $\mathbf{X_0}$.

Podstawiając współrzędne:

$\vec N \cdot (X - X_0)$
$[A,B,C] \cdot [x-x_0,y-y_0,z-z_0]=0$
$Ax+By+Cz+(-Ax_0-By_0-Cz_0)=0$
$Ax+By+Cz+D=0$
Jest to algebraiczna postać płaszczyzny. D to dowolna stała. Możmy powiedzieć, że -D to rzut punktu $\mathbf{X_0}$ na wektor $\mathbf{\vec N}$. Jest to minimalna odległość płaszczyzny od początku układu współrzędnych. $A,B,C,D mogą przyjmować dowolne wartości, tak by $\mathbf{|\vec N|} \neq 0$.

Równanie płaszczyzny możemy też zapisać jako:

$\vec N \cdot (X - X_0)$
$\vec N \cdot X - \vec N \cdot X_0)$
$\vec N \cdot X + D$
Bardzo często musimy określić płaszczyznę mając jej trzy punkty. Punkty powinny być niewspółliniowe. Budujemy z nich dwa wektory równoległe do płaszczyzny, ich iloczyn wektorowy to normalna.

Mając dowolny punkt płaszczyzny $\mathbf{p}$ minimalna odległość do początku układu współrzędnych to rzut wektora $\mathbf{[p_x-0,p_y-0,p_z-0]}$ na wektor $\mathbf{\vec N}$. Pod warunkiem, że wektor normalny jest znormalizowany jest to ich iloczyn skalarny.

Prawo załamania

Mając dany wektor promienia padający na granice dwóch ośrodków $\mathbf{\vec i}$, współczynniki załamania obu ośrodków $\mathbf{n_1}$ i $\mathbf{n_2}$, normalną w punkcie padania $\mathbf{\vec N}$ wyznaczymy wektor załamany $\mathbf{\vec t}$.

Zakładmy, że wektor normalny $\mathbf{\vec N}$, padający $\mathbf{\vec i}$ jak i załamany $\mathbf{\vec t}$ są znormalizowane.


  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
    
    
    
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
    α
    β
    
    
    
      
        t
        1
      
      
    
    
      t
      
    
    
      i
      1
      
    
    
      
        N
      
      
    
    
      
        t
        2
      
      
    
    
      2
      
        i
        
      
    
    
      i
      
    
    
      n
      1
    
    
      n
      2
    
  


Ponieważ wektory $\mathbf{\vec i}$ i $\mathbf{\vec t}$ są znormalizowane to:

$\left | \vec{i_2} \right | = \sin \alpha \qquad\qquad
\left | \vec{i_1} \right | = \cos \alpha \qquad\qquad
\left | \vec{t_2} \right | = \sin \beta \qquad\qquad
\left | \vec{t_1} \right | = \cos \beta$
Z rzutów wektorów $\mathbf{\vec i}$ i $\mathbf{\vec t}$ na $\mathbf{\vec N}$:

$\vec i \vec N = -\cos \alpha \qquad\qquad
\vec t \vec N = -\cos \beta$
Znając długości wektorów $\mathbf{\left | \vec{i_1} \right |}$ i $\mathbf{\left | \vec{t_1} \right |}$ i ich zwrot możemy zapisać:

$\vec{i_1} = -\vec N \cos \alpha \qquad\qquad
\vec{t_1} = -\vec N \cos \beta$
Z prawa Snelliusa:

$n_1 \sin \alpha = n_2 \sin \beta$

$n_1 \left | \vec{i_2} \right |= n_2 \left | \vec{t_2} \right |$
Ponieważ wektory $\mathbf{\vec{i_2}}$ i $\mathbf{\vec{t_2}}$ mają zgodny zwrot i kierunek:

$n_1 \vec{i_2} = n_2 \vec{t_2}$

$n_1 ( \vec i - \vec i_1 ) = n_2 \vec{t_2}$

$n_1 ( \vec i + \vec N \cos \alpha ) = n_2 \vec{t_2}$

$\vec{t_2} = \displaystyle\frac{n_1}{n_2}(\vec i + \vec N \cos \alpha)$
Teraz wyznaczmy $\mathbf{\vec{t_1}}$:

$\begin{split}\vec{t_1} &= -\vec N \cos \beta \\
&= -\vec N \left | \vec t_1 \right | \\
&= -\vec N \sqrt{1-\left | \vec t_2 \right |^2} \\
&= -\vec N \sqrt{1-\sin^2 \beta} \\
&= -\vec N \sqrt{1- \displaystyle\frac{n_1}{n_2}^2 \sin^2 \alpha} \\
&= -\vec N \sqrt{1- \displaystyle\frac{n_1}{n_2}^2 ( 1 - \cos^2 \alpha )}
\end{split}$
Mając $\mathbf{\vec{t_1}}$ i $\mathbf{\vec{t_2}}$:

$\begin{split}\vec t &= \vec{t_1} + \vec{t_2} \\
&= \displaystyle\frac{n_1}{n_2}(\vec i + \vec N \cos \alpha) - \vec N \sqrt{1- \displaystyle\frac{n_1}{n_2}^2 ( 1 - \cos^2 \alpha )} \\
&= \displaystyle\frac{n_1}{n_2}\vec i + \vec N ( \displaystyle\frac{n_1}{n_2} \cos \alpha - \sqrt{1- \displaystyle\frac{n_1}{n_2}^2 ( 1 - \cos^2 \alpha )})
\end{split}$
Otrzymany wektor $\mathbf{\vec{t}}$ jest znormalizowany.

Promień padający po w kierunku normalnej nie zostanie załamany.

Jeśli $\mathbf{n_1 < n_2}$ wraz ze zwiększaniem kąta $\mathbf{\alpha}$ kąt $\mathbf{\beta}$ będzie się zwiekszał, ale wolniej. Jak $\mathbf{\alpha}$ będzie dążył do $90^\circ$ to $\mathbf{\beta}$ będzie dążył do $arcsin\frac{n_1}{n_2}$, kąta mniejszego od $90^\circ$. Jeśli $\mathbf{n_2 < n_1}$ wraz ze zwiększaniem kąta $\mathbf{\alpha}$ kąt $\mathbf{\beta}$ będzie się zwiększał, ale szybciej. Kąt $\mathbf{\beta}$ zmienia się zgodnie z $arcsin(\frac{n_1}{n_2}\sin\alpha$). Dla pewnego granicznego kąta $\mathbf{\alpha}$ wartość z której liczymy arcsin będzie większa niż jeden. Nastąpi to dla kąta granicznego $arcsin\frac{n_2}{n_1}$. Po przekroczeniu tego kąta promień załamany zanika i następuje całkowite wewnętrzne odbicie.

W naszym równaniu na wektor promienia załamanego zjawisko całkowitego wewnętrznego odbicia następuje jeśli:

$1- \displaystyle\frac{n_1}{n_2}^2 ( 1 - \cos^2 \alpha ) < 0$



W odniesieniu do raytracing'u należy jeszcze uwzględnić jak zmienia się energia promienia odbitego i załamanego. Po pierwsze zakładamy, że istnieje współczynnik pochłaniania energii promienia odbitego i załamanego. Samo podział energii (a także polaryzacji) dla dielektryków definiuje równanie Fresnel'a. Sam promień przechodząc przez medium powinien tracić energię (Prawo Beer'a albo współczynniki pochłaniania liniowego i wykładniczego).

W niektórych mediach współczynnik załamania może się zmieniać w sposób nieliniowy w danym materiale i tak też będzie poruszać się promień światła w materiale.

Przykład implementacji w C#:
public Ray RefractedRay
{
    get
    {
        Debug.Assert(Exists);

        if (m_refracted_ray == null)
        {
            double n = RefractionIndiceN1 / RefractionIndiceN2;
            double cos_alpha = -SourceRay.Dir * ShadeNormal;
            double cos_beta_2 = 1 - n * n * (1 - cos_alpha * cos_alpha);

            if (cos_beta_2 > 0)
            {
                Scene.Statistics.RaysRefracted++;
                Scene.Statistics.RaysCreated++;

                m_refracted_ray = new Ray()
                {
                    Dir = n * SourceRay.Dir +
                        (n * cos_alpha - Math.Sqrt(cos_beta_2)) * ShadeNormal,
                    SourceIntersection = this,
                    Start = Pos,
                    Depth = SourceRay.Depth + 1,
                };
            }
            else
            {
                Scene.Statistics.TotalInternalReflections++;
            }
        }

        return m_refracted_ray;
    }
}

2011-07-18

Współrzędne barycentryczne

Ograniczymy się tylko do wersji 2D i skupimy się tylko na zastosowaniu w trójkącie.

  
    
      
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
    P1
    P0
    P2
    v
    u
    
    
    
    P
    
  

Współrzędne barycentryczne to para (u,v). Można powiedzieć, że jest to punkt w układzie współrzędnych którego osie to boki trójkąta. Konwersja pomiędzy układem barycentrycznym, a ortogonalnym:

$P=P_0+\vec u + \vec v$
$P=P_0+u(P_1-P_0)+v(P_2-P_0)$
$P=P_0+uP_1-uP_0+vP_2-vP_0$
$P=P_0(1-v-u)+P_{1}u+P_{2}v$
Widzimy, że punkt $\mathbf{P}$ jest liniową kombinacją $\mathbf{P_0}$, $\mathbf{P_1}$ i $\mathbf{P_2}$. Tak naprawdę współrzędne barcentryczne to trójka liczb, przy czym ta trzecia to $\mathbf{1-u-v}$.

Współrzędne barycentryczne wyznaczają punkt wewnątrz trójkąta jeśli $\mathbf{0<=u<=1}$ i $\mathbf{0<=v<=1}$ i $\mathbf{0<=v+u<=1}$. Konwersja z układu ortgonalnego na układ barycentryczny:

  
    
      
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
    P1
    P0
    P2
    P
    
    
  
Współrzędne barycentryczne wyznaczamy z proporcji pól trójkątów:

$u=\displaystyle\frac{\triangle(P, P0, P2)}{\triangle(P0, P1, P2)}$


$v=\displaystyle\frac{\triangle(P, P0, P1)}{\triangle(P0, P1, P2)}$

Pola trójkątów najlepiej policzyć z iloczynu wektorowego. Wzory te działają tylko dla punktu wewnątrz trójkąta.

Przeanalizujmy współrzędna u. Jeśli znajdzie się ona na boku trójkąta $\mathbf{\overline{P0P1}}$ pole trójkąta $\mathbf{\triangle(P, P0, P2)}$ jest równe zeru i tym samym współrzędna u. Wraz z przemieszaniem się punktu P w stronę punktu P1 pole trójkąta $\mathbf{\triangle(P, P0, P2)}$ dąży do pola trójkąta $\mathbf{\triangle(P0, P1, P2)}$, czyli współrzędna u dąży do jeden. Jeśli współrzędna wyjdzie poza trójkąt pole (powinno być, w naszym przypadku nie jest ujemne) lub większe od 1. To samo tyczy się pozostałych współrzędnych barycentrycznych.

Jeśli trójkąty $\mathbf{\triangle(P, P0, P2)}$ lub $\mathbf{\triangle(P, P0, P1)}$ będą mieć w sumie pole większe od pola trójkąta $\mathbf{\triangle(P0, P1, P2)}$ to niewątpliwie punkt P musi być poza trójkątem. Czyli punkt jest w trójkącie jeśli $\mathbf{0<=v+u<=1}$. Ten warunek musi być spełniony dla dowolnej pary współrzędnych barycentrycznych.

Współrzędne barycentryczne mają zastosowanie podczas teksturowania. Dla punktu P wewnątrz trójkąta liczymy jego współrzędne barycentryczne. Dalej biorąc nową trójkę współrzędnych tekstury liczymy współrzędną tekstury z współrzędnych barycentrycznych.

Reguła prawej dłoni

Reguła ta wyznacza nam zwrot iloczynu wektorowego. Jeśli kciuk wskaże pierwszą pierwszy wektor iloczynu. Pozostałe palce drugi wektor. To z wnętrza dłoni będzie wychodził wektor wynikowy. Dłoń jest rozwarta. Wszystkie palce są w jednej płaszczyźnie. Kciuk jest ustawiony prostopadle do pozostałych palców.

Dla układów prawoskrętnych reguła także wyznacza nam wizualny zwrot wektora. Dla układów lewoskrętnych musimy do tego stosować lewą rękę. Niezależnie od układu współrzędnych iloczyn wektorowy liczymy tak samo (jego wartość nie zmienia się).

Dodatkowo kierunek od kciuka do pozostałych palców wyznacza nam obrót wokół wektora wychodzącego z dłoni przy dodatnich kątach obrotu.

Tutaj został podany jeden ze sposobów jej definiowania. Można wykorzystać zaciśniętą pięść. Dłoń z palcami ustawionymi jak osie układu współrzędnych 3D. Można tą regułę tak zmodyfikować, że to kciuk wyznacza nam wektor wynikowy.

Skrętność układu współrzędnych

Układ współrzędnych może być lewo albo prawoskrętny. Własność ta definiuje jak wizualizujemy nasz układ współrzędnych. W którą stronę pokażemy zwrot iloczynu wektorowego. Z tym zaś wiąże się kierunek obrotu wektora wokół innego wektora i jak mierzymy kąt między wektorami ze znakiem.

Właściwość $\mathbf{X \times Y = Z}$ nie zależy od rodzaju układu współrzędnych.

W układzie lewoskrętnym jeśli X wskazuje w prawo, Y do góry, to Z wskazuje wgłąb sceny. W układzie prawoskrętnym Z wskazuje w stronę obserwatora sceny. Układ prawoskrętny to np. OpenGL, układ lewoskrętny to np. DirectX.

Jeśli chodzi o kąty. Dla układu prawoskrętnego bierzemy prawą rękę. Dla lewoskrętnego lewą. Kciuk wyznacza nam wektor wokół którego chcemy obrócić inny wektor. Palce złożone w pięść wyznaczają kierunek obrotu dla dodatnich wartości kąta.

We wszystkich przykładach posługuję się układem lewoskrętnym.

Iloczyn mieszany wektorów

Jest to liczba definiowana jako:

$\vec A \cdot (\vec B \times \vec C)$
Jest wartość bezwzględna stanowi objętość równoległościanu definiowanego przez te trzy wektory. Jeśli wszystkie trzy wektory leża na jednej płaszczyźnie wtedy iloczyn mieszany ma wartość zero.

Właściwości:

$\vec A \cdot (\vec B \times \vec C) = \vec B \cdot (\vec C \times \vec A) = \vec C \cdot (\vec A \times \vec B)$

$\vec A \cdot (\vec B \times \vec C) = \begin{vmatrix}a_1 & a_2 & a_3 \\ b_1 & b_2 & b_3 \\ c_1 & c_2 & c_3 \end{vmatrix}$

Rzut wektora na wektor


  
    
      
    
    
      
    
    
      
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
      
      
    
    
      
      
    
    
    
    θ
    A
    B
    C
    
      
      
    
  


Z właściwości iloczynu skalarnego:

$\vec A \cdot \vec B=\left | \vec A \right | \, \left | \vec B \right | \cos \theta$
, stąd:

$\cos \theta = \displaystyle\frac{\vec A \cdot \vec B}{\left | \vec A \right | \, \left | \vec B \right |}$
Z drugiej strony:

$\cos \theta = \displaystyle\frac{\left | \vec C \right |}{\left | \vec A \right |}$
Z porównania:

$\left | \vec C \right | = \displaystyle\frac{\vec A \cdot \vec B}{\left | \vec B \right |}$
Otrzymana wartość jest ze znakiem. Wektor $\mathbf{\vec C}$:

$\vec C = \displaystyle\frac{\vec A \cdot \vec B}{\left | \vec B \right |}\hat B$
Jeśli $\mathbf{\vec B}$ jest wektorem jednostkowym to:

$\vec C = (\vec A \cdot \vec B) \hat B$

Badanie kąta pomiędzy wektorami

Iloczyn skalarny dwóch wektorów to:

$a \cdot b=\left | a \right | \, \left | b \right | \cos \theta$
, stąd:

$\cos \theta = \displaystyle\frac{a \cdot b}{\left | a \right | \, \left | b \right |}$
Ponieważ zawsze $\left | a \right | \, \left | b \right | >= 0$ to:

$\begin{array}{lll}
a \cdot b > 0 \Rightarrow \cos \theta > 0 \Rightarrow -90^\circ < theta < 90^\circ\\ a \cdot b = 0 \Rightarrow \cos \theta = 0 \Rightarrow \theta = \pm 90^\circ\\ a \cdot b < 0 \Rightarrow \cos \theta < 0 \Rightarrow 90^\circ < \theta < 270^\circ \end{array}$
Z właściwości tych możemy skorzystać do szybkiego zbadania zbieżności wektorów. Czy promień zmierza w kierunku obiektu. Czy trójkąt jest zwrócony przodem do kamery. By na wczesnym etapie uciąć jakieś obliczenia.

Iloczyn skalarny wektorów

Jest liczbą. Można go zdefiniować w dowolnie wymiarowej przestrzeni. Iloczyn skalarny dwóch wektorów $\mathbf{\vec a}$ i $\mathbf{\vec b}$ definiujemy jako:

$a \cdot b = \sum_{i=1}^n a_ib_i = a_1b_1 + a_2b_2 + \cdots + a_nb_n$
Jeśli wektory potraktować jako kolumnowy macierzy to:

$a \cdot b = a^{T}b = b^{T}a$
W interpretacji geometrycznej:

$a \cdot b=\left | a \right | \, \left | b \right | \cos \theta$
W szczególności jeśli wektory są jednostkowe to iloczyn skalarny jest cosinusem kąta między nimi. Jeśli wektory są do siebie prostopadłe to ich iloczyn skalarny jest równy zero, zaś jeśli równoległe to jeden.

Właściwości:

$a \cdot b = b \cdot a$
$a \cdot (b+c) = a \cdot b + a \cdot c$
$a \cdot (rb+c) = r(a \cdot b) + a \cdot c$
$r_1 a \cdot r_2 b = r_1 r_2 (a \cdot b)$
$ |a \times b|^2 = |a|^2 |b|^2 - (a \cdot b)^2$ (z porównania z iloczynem wektorowym)

Iloczyn wektorowy

Istnieje tylko w przestrzeni trójwymiarowej. Jego wynikiem jest wektor $\mathbf{\vec C}$ normalny do płaszczyzny zawierającej dwa inne wektory $\mathbf{\vec A}$ i $\mathbf{\vec B}$, których jest produktem. Jego długość równa jest polu równoległoboku zbudowanego na wektorach $\mathbf{\vec A}$ i $\mathbf{\vec B}$. Zaś połowa długości to pole trójkąta, którego dwa boki to $\mathbf{\vec A}$ i $\mathbf{\vec B}$.

Jego zwrot wyznacza reguła prawej dłoni. Przy czym wizualnie możemy go skierować na dwa sposoby w zależności od skrętności układu współrzędnych.

Tutaj mamy przykład układu lewoskrętnego:


  
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
    Y
    X
    
    Z
    
      
      
    
    
      
      
    
    A
    B
    
      
      
    
    C
    
    
    
    Θ
  


Iloczyn oznaczamy jako:

$\vec C = \vec A \times \vec B$
Sposób jego obliczania:

$\begin{bmatrix}a_1 \\ a_2 \\ a_3 \end{bmatrix} \times \begin{bmatrix}b_1 \\ b_2 \\ b_3 \end{bmatrix} = \begin{bmatrix}a_2b_3 - a_3b_2 \\ a_3b_1 - a_1b_3 \\ a_1b_2 - a_2b_1 \end{bmatrix}$
Jego wartość:

$\left | \vec C \right |= \left | A \right |\left | B \right |\sin\theta$
Iloczyn wektorowy wyznacza nam także zwroty wersorów układu współrzędnych:

$\hat x \times \hat y = \hat z$
$\hat y \times \hat z = \hat x$
$\hat z \times \hat x = \hat y$
Właściwości:

$a \times b = -b \times a = - (b \times a)$
$a \times (b + c) = a \times b + a \times c$
$(ra) \times b = a \times (rb) = r(a \times b)$
$ |a \times b|^2 = |a|^2 |b|^2 - (a \cdot b)^2$ (z porównania z iloczynem skalarnym)
Jeśli dwa wektory są do siebie równoległe to ich iloczyn wektorowy równy jest zeru.

2011-07-17

Intersekcja promienia z obiektami - możliwe problemy

Promień pada na powierzchnię i odbija się od niej. Podczas wykrywania nowej intersekcji wykrywamy ją z obiektem od którego się odbiliśmy co gorsza dokładnie w tym samym punkcie. Przyczyną są niedokładności obliczeniowe.

Istnieją dwa sposoby radzenia sobie z sytuacją. W pierwszym przesuwamy punkt startu promienia odbitego wzdłuż jego kierunku o niewielką wartość, która pozwala nam przezwyciężyć błąd obliczeniowy. Ale równocześnie jeśli nasza powierzchnia jest wypukła może się zdarzyć, że promień przejdzie na drugą stronę powierzchni. Poza tym ustalenie wartości przesunięcia też jest dosyć problematyczne. Musi być ściśle zgrane z odstępami pomiędzy obiektami i ich wymiarami. Wymiary obiektów ani odstępy pomiędzy nimi nie mogą być mniejsze niż pewna graniczna wartość tego przesunięcia. Samo przesunięcie musi być większe niż błąd obliczeniowy i tutaj jest też duży problem jeśli chcemy by wartość ta była naprawdę minimalna.

W drugiej metodzie pamiętamy w co i z której strony ostatnio uderzyliśmy. Dzięki temu dokładnie kontrolujemy sytuację. Jeśli uderzenie nastąpiło z zewnątrz to ignorujemy wszelkie ponowne kolizje z obiektem. Jeśli od wewnątrz to dopuszczamy ponowną kolizję z tym samym obiektem. Dużo większy problem mamy wtedy gdy nasza powierzchnia opisana jakimś wzorem matematycznym będzie dużo bardziej skomplikowana niż np. sfera. Wtedy prawdopodobnie trzeba się jednak zacząć posiłkować jakimś minimalnym przesunięciem pomiędzy dwoma punktami uderzenia.

Zupełnie osobnym problemem jest sytuacja gdy dwa np. trójkąty przystają do siebie. Promień pada blisko boku przystającego w trójkąt 1, odbija się i wykrywana jest kolizja z trójkątem 2. Dystans jest wtedy bardzo mały, na granicy błędu obliczeniowego i na podstawie tego powinniśmy taką intersekcję odrzucać.