2011-09-01

Skalowanie - zmiany w kodzie sfery

Kod oryginalny:
public override Intersection GetIntersection(Ray a_ray)
{
    bool backHit = false;

    Vector3 c = Pos - a_ray.Start;
    double c2 = c.Length * c.Length;
    double r2 = Radius * Radius;
            
    double dist;

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

            if (OneSide)
                return Scene.NoIntersection;
            else
            {
                double v = c * a_ray.Dir;
                double m2 = r2 - (c2 - v * v);

                dist = v + Math.Sqrt(m2);
            }
        }
        else
            return Scene.NoIntersection;
    }
    else
    {
        double v = c * a_ray.Dir;
        double m2 = r2 - (c2 - v * v);

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

            if (OneSide)
                return Scene.NoIntersection;
            else
                dist = v + Math.Sqrt(m2);
            }
        }

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

public override Vector3 GetNormal(Intersection a_intersection)
{
    if (a_intersection.BackHit)
        return (Pos - a_intersection.Pos).Normalized;
    else
        return (a_intersection.Pos - Pos).Normalized;
}
Nowy kod:
public Ray Transform(Matrix4 a_matrix)
{
    return new Ray()
    {
        Dir = (a_matrix.Rotation * this.Dir).Normalized,
        Start = a_matrix * this.Start,
        SourceIntersection = this.SourceIntersection,
        Depth = this.Depth

    };
}

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

public override Vector3 GetNormal(Intersection a_intersection)
{
    if (a_intersection.BackHit)
        return -(LocalToWorldNormal * a_intersection.UVW).Normalized;
    else
        return (LocalToWorldNormal * a_intersection.UVW).Normalized;
}
Główne zmiany są na początku badania intersekcji kiedy promień jest transformowany do lokalnego układu współrzędnych. Dzięki temu z obliczeń wylatuje Pos. Dodatkowo poprzenosiłem wgłąb wyliczenia niektórych zmiennych do momentu, aż są one potrzebne. Na samym końcu przed zwróceniem wyniku intersekcji wyliczamy miejsce uderzenia i dystans w współrzędnych świata.

W kodzie na wyliczenie normalnej korzystamy od teraz z specjalnej macierzy na transformację normalnych. Zauważmy, że współrzędne UVW są zmapowane na sferę.

Pozostały kod na wyliczanie UVW, UV, tangensów nie ulega zmianie.

Brak komentarzy:

Prześlij komentarz