2011-09-01

Skalowanie - zmiany w kodzie płaszczyzny

Zamian wymagał tylko kod intersekcji z promieniem. W przeciwieństwie do sfery kod zwracający normalną w punkcie nie uległ zmiany. Normalna jest dla płaszczyzny wszędzie taka samo i jako taka została wcześniej wyliczona.

Oryginalny kod
public override Intersection GetIntersection(Ray a_ray)
{
    float denom = Normal * a_ray.Dir;

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

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

    if (!denom.IsZero())
    {
        float 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;
}
Zmieniony kod:
public override Intersection GetIntersection(Ray a_ray)
{
    Ray ray_local = a_ray.Transform(WorldToLocal);

    bool backHit = false;
    float dist;

    if (ray_local.PrevHit == this)
    {
        if (ray_local.PrevBackHit)
        {
            backHit = true;

            if (OneSide)
                return Scene.NoIntersection;
            else
            {
                float v = -(ray_local.Start * ray_local.Dir);
                float m2 = Radius * Radius - (ray_local.Start.SqrLen - v * v);
                dist = v + (float)Math.Sqrt(m2);
            }
        }
        else
            return Scene.NoIntersection;
    }
    else
    {
        float c2 = ray_local.Start.SqrLen;
        float r2 = Radius * Radius;

        if (c2 > r2)
        {
            float v = -(ray_local.Start * ray_local.Dir);
            if (v <= 0)
                return Scene.NoIntersection;
            else
            {
                float m2 = r2 - (c2 - v * v);
                if (m2 < 0)
                    return Scene.NoIntersection;
                else
                    dist = v - (float)Math.Sqrt(m2);
            }
        }
        else
        {
            backHit = true;

            if (OneSide)
                return Scene.NoIntersection;
            else
            {
                float v = -(ray_local.Start * ray_local.Dir);
                float m2 = r2 - (c2 - v * v);
                dist = v + (float)Math.Sqrt(m2);
            }
        }
    }

    var pos = ray_local.Start + ray_local.Dir * dist;
    pos = LocalToWorld * pos;
    dist = (pos - a_ray.Start).Length;

    return new Intersection()
    {
        SceneObject = this,
        SourceRay = a_ray,
        Dist = dist,
        Scene = Scene,
        BackHit = backHit,
        Pos = pos
    };
}
Zmiany polegały na dodaniu transformacji promienia z współrzędnych świata do lokalnego na początku i policzeniu punktu uderzenia i dystansu w współrzędnych świata na końcu. Dodatkowo w układzie lokalnym płaszczyzna leży (w moim przypadku) w płaszczyźnie XZ, tak więc normalna do wersor Y, zaś dystans płaszczyzny do środka układu współrzędnych to 0. To pozwala nam trochę uprościć kod.

Brak komentarzy:

Prześlij komentarz