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;
}

Brak komentarzy:

Prześlij komentarz