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