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