2011-12-09

Klasy promieni

Wraz z rozwojem raytracera kod promienia musiał się zmienić i to znacznie. No dobra może nie musiał aż tak.

Po pierwsze intersekcje zacząłem sprawdzać w lokalnym układzie współrzędnych.

Po drugie testowanie cieni półprzeźroczystych wymagało wielu testów dla promienia podążającego w tym samym kierunku, tak że zmienia się tylko punkt startu dla kolejnych powierzchni półprzeźroczystych. Pokusa manipulowania danymi promienia okazała się duża. Z drugiej strony promień jest wykorzystywany w wielu miejscach. Po takiej manipulacji i przed powrotem z funkcji trzeba go przywrócić do stanu pierwotnego, nie wspominając o innych możliwych niepożądanych interakcjach, kiedy zmodyfikujemy promień z klasy intersekcji, a później chcemy coś z niej liczyć - wiele elementów tej klasy jest liczona w sposób opóźniony na żądanie. Tak więc modyfikacje promieni musiały zostać zakazane, a promień musiał stać się klasą immutable. Tzn. poprzednio nie był immutable, ale raczej go nie modyfikowałem. Teraz zostało to zakazane jawnie.

Wyleciała z niego przede wszystkim właściwość wskazująca na źródłową intersekcję. Została ona dodana jako parametr wielu funkcji. Wraz z tym z promienia poleciało wiele funkcji, których wartość wymagała do obliczenia intersekcji. Okazało się, że kod dało się bez problemu przekształcić, tak by się bez nich obejść, ale w kodzie promienia musiała się pojawić jedna dodatkowa informacja mówiąca nam o tym z jakim promieniem mamy do czynienia: odbitym czy załamanym. Bez tej informacji wiele funkcji nie może działać.

Stary kod promienia:
public class Ray
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private Vector3 m_dir;

    public int Depth = 0;
    public Vector3 Start;
    public Intersection SourceIntersection;
    public bool Refracted;

    public RenderableObject PrevHit
    {
        get
        {
            if (SourceIntersection != null)
                return SourceIntersection.SceneObject;
            else
                return null;
        }
    }

    public bool PrevBackHit
    {
        get
        {
            if (SourceIntersection != null)
                return SourceIntersection.BackHit;
            else
                return false;
        }
    }

    public Vector3 Dir
    {
        get
        {
            return m_dir;
        }
        set
        {
            Debug.Assert(value.IsNormalized);
            m_dir = value;
        }
    }

    public Vector3 HitPoint(float a_distance)
    {
        return Start + Dir * a_distance;
    }

    public override string ToString()
    {
        return String.Format("start: {0}; direction: {1}; depth: {2}",
            Start, Dir, Depth);
    }

    public void Transform(Matrix4 a_matrix, out Vector3 a_local_dir, out Vector3 a_local_start)
    {
        a_local_dir = (a_matrix.Rotation * Dir).Normalized;
        a_local_start = a_matrix * Start;
    }
}

Nowy kod:

public enum RaySurfaceSide
{
    /// 
    /// i.e. Camera ray, LightTestRay.
    /// 
    NonDetermined, 

    /// 
    /// i.e. RefractedRay. ShadowRay.
    /// 
    RefractedSide,

    /// 
    /// i.e. ReflectedRay, ShadowRay.
    /// 
    ReflectedSide
}

public abstract class Ray
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private Vector3 m_dir;

    public int Depth { get; protected set; }
    public Vector3 Start { get; protected set; }
    public RaySurfaceSide RaySurfaceSide { get; protected set; }

    protected Ray(Scene a_scene)
    {
        a_scene.Statistics.RaysCreated++;
    }

    public Vector3 Dir
    {
        get
        {
            return m_dir;
        }
        protected set
        {
            Debug.Assert(value.IsNormalized);
            m_dir = value;
        }
    }

    public Vector3 HitPoint(float a_distance)
    {
        return Start + Dir * a_distance;
    }

    public override string ToString()
    {
        return String.Format("{3}, Start: {0}; Dir: {1}; Depth: {2}, Type: {4}",
            Start, Dir, Depth, GetType().Name, RaySurfaceSide);
    }

    public void Transform(Matrix4 a_matrix, out Vector3 a_local_dir, out Vector3 a_local_start)
    {
        a_local_dir = (a_matrix.Rotation * Dir).Normalized;
        a_local_start = a_matrix * Start;
    }
}

Brak komentarzy:

Prześlij komentarz