public Tuple ReflectedColor(Precomputation comp, int remaining) { if (comp.Object.Material.Reflective == 0 || remaining <= 0) { return(new Tuple(0, 0, 0, 0)); } Ray reflectRay = new Ray(comp.OverPoint, comp.ReflectVector); Tuple colour = ColourAt(this, reflectRay, remaining - 1); return(colour * comp.Object.Material.Reflective); }
public static Tuple ColourAt(World world, Ray ray, int remaining) { Intersection[] worldIntersections = IntersectWorld(world, ray); Intersection hit = Intersect.Hit(worldIntersections); if (hit != null) { Precomputation comps = Intersect.PrepareComputations(hit, ray); return(ShadeHit(world, comps, remaining)); } else { return(new Tuple(0, 0, 0, 0)); } }
public static Tuple ShadeHit(World world, Precomputation comps, int remaining) { bool shadowed = IsShadowed(world, comps.OverPoint); Tuple Colour = Material.Lighting(comps.Object.Material, comps.Object, world.SceneLight, comps.OverPoint, comps.EyeVector, comps.NormalVector, shadowed); Tuple reflectedColor = world.ReflectedColor(comps, remaining); Tuple refractedColor = RefractedColor(world, comps, remaining); Material m = comps.Object.Material; if (m.Reflective > 0f && m.Transparency > 0f) { float reflectance = Schlick(comps); return(Colour + reflectedColor * reflectance + refractedColor * (1 - reflectance)); } else { return(Colour + reflectedColor + refractedColor); } }
public static float Schlick(Precomputation comp) { float cos = comp.EyeVector.Dot(comp.NormalVector); if (comp.n1 > comp.n2) { float ratio = comp.n1 / comp.n2; float sin2_t = ratio * ratio * (1.0f - (cos * cos)); if (sin2_t > 1.0) { return(1.0f); } float cos_t = MathF.Sqrt(1.0f - sin2_t); cos = cos_t; } float r0 = ((comp.n1 - comp.n2) / (comp.n1 + comp.n2)) * ((comp.n1 - comp.n2) / (comp.n1 + comp.n2)); return(r0 + (1 - r0) * MathF.Pow((1 - cos), 5)); }
public static Tuple RefractedColor(World world, Precomputation comp, int remaining) { if (comp.Object.Material.Transparency == 0 || remaining == 0) { return(new Tuple(0, 0, 0)); } float n_ratio = comp.n1 / comp.n2; float cos_i = comp.EyeVector.Dot(comp.NormalVector); float sin2_t = (n_ratio * n_ratio) * (1 - (cos_i * cos_i)); if (sin2_t > 1) { return(new Tuple(0, 0, 0)); } float cos_t = MathF.Sqrt(1.0f - sin2_t); Tuple direction = comp.NormalVector * (n_ratio * cos_i - cos_t) - comp.EyeVector * n_ratio; Ray refract_ray = new Ray(comp.UnderPoint, direction); return(ColourAt(world, refract_ray, remaining - 1) * comp.Object.Material.Transparency); }
public static Precomputation PrepareComputations(Intersection i, Ray ray, Intersection[] optionalXS = null) { if (optionalXS == null) { optionalXS = new Intersection[1]; optionalXS[0] = i; } List <Shape> containers = new List <Shape>(); Precomputation comp = new Precomputation(); for (int index = 0; index < optionalXS.Length; index++) { if (optionalXS[index] == i) { if (containers.Count == 0) { comp.n1 = 1.0f; } else { comp.n1 = containers[containers.Count - 1].Material.Refractive_index; } } if (containers.Contains(optionalXS[index].Object)) { containers.Remove(optionalXS[index].Object); } else { containers.Add(optionalXS[index].Object); } if (optionalXS[index] == i) { if (containers.Count == 0) { comp.n2 = 1.0f; } else { comp.n2 = containers[containers.Count - 1].Material.Refractive_index; } break; } } //Precomputation comp = new Precomputation(); comp.T_Value = i.T_Value; comp.T_Value_Tuple = i.T_Value_Tuple; comp.Object = i.Object; comp.Point = ray.Position(comp.T_Value_Tuple); comp.EyeVector = -ray.Direction; comp.NormalVector = Shape.NormalAt(comp.Object, comp.Point); if (comp.NormalVector.Dot(comp.EyeVector) < 0) { comp.Inside = true; comp.NormalVector = -comp.NormalVector; } else { comp.Inside = false; } comp.OverPoint = comp.Point + (comp.NormalVector * Arithmetic.EPSILON); comp.UnderPoint = comp.Point - (comp.NormalVector * Arithmetic.EPSILON); comp.ReflectVector = Tuple.Reflect(ray.Direction, comp.NormalVector); return(comp); }