// Obtain the colour of a ray/model intersection public Colour Shade(Intersection hit, Ray r, int level, double weight) { if (level > traceMax) { return(background); // Too deep } // Get the surface normal var normal = hit.Model.Normal(hit.Location); // If looking at the inside of a model (e.g. rhs of CSGDifference; or transparent object) // then the normal will be inverted if ((normal * r.Direction) > 0.0) { normal = -normal; } var colour = new Colour(); // Point p, where shadow ray originates, is elevated from the model // surface to prevent erroneous self-shadowing. var p = hit.Location + normal * rayOffset; var filter = new Colour(1.0); foreach (var l in lights) { // If shadowing, determine if l is blocked // If only blocked by transparent objects then return the // overall filter colour in filter; if (!(shadow && Shadowed(p, l, out filter))) { colour += (filter * (l.Illumination(hit, normal))); } } var materialHit = hit.Model.Material; if (materialHit == null) { materialHit = Material.NullMaterial; } // Add ambient light colour += ambient * materialHit.GetPigment(hit.Location); var reflectance = materialHit.Reflectance; // Do reflections, but only if they will make a visible contribution if ((reflectance != 0.0) && (reflectance * weight > minWeight) && (level <= traceMax)) { // launch reflected ray from rayOffset above the surface var rray = new Ray(hit.Location + normal * rayOffset, (normal * (-2.0 * (r.Direction * normal)) + r.Direction)); var rhit = Intersect(rray); if (rhit.Model != null) { if (rhit.Model.Material == null) { throw new AuroraException("Scene.Trace Model has null material"); } colour += Shade(rhit, rray, level + 1, reflectance * weight) * reflectance; } // Reflected into space else { colour += background * reflectance; } } if (materialHit.Transparent) { // The transmitted (or internally reflected) ray Ray tray; // The medium for tray var medium = materialHit; if (materialHit.Ior != hit.Medium.Ior) // Refracted? { var eta = hit.Medium.Ior / materialHit.Ior; var ci = normal * -r.Direction; var disc = 1.0 + eta * eta * (ci * ci - 1.0); // disc discriminates between refraction and tir if (disc < 0.0) { // TODO: Why did this originally just return White? // Total internal reflection // launch transmitted ray from rayOffset above the surface tray = new Ray(hit.Location + normal * rayOffset, (normal * (-2.0 * (r.Direction * normal)) + r.Direction)); medium = hit.Medium; // return new Colour(1.0, 1.0, 0.0); } else { // Refraction // launch transmitted ray from rayOffset beyond the surface var tdir = (eta * r.Direction + (eta * ci - Math.Sqrt(disc)) * normal).Normalise(); tray = new Ray(hit.Location + tdir * rayOffset, tdir); } } else { // Simple transmission (identical refractive indices) tray = new Ray(hit.Location + r.Direction * rayOffset, r.Direction); } var thit = Intersect(tray); if (thit.Model != null) { var w = medium.Filter.Lightness() * weight; colour += Shade(thit, tray, level + 1, w) * medium.Filter; } else { colour += background * medium.Filter; } } return(colour); }
public void MakeTransparent(Colour tfilter, double tior) { filter = tfilter; ior = tior; transparent = true; }
public Pigment(Colour d) { a = d; }
public Material(Colour c, Finish f) : this(new Pigment(c), f) { }