// This is where the magic happens! Trace a ray... Vector3 Trace(Ray ray, short depth, bool drawDebugLine, bool absorb = false) { if (depth == maxDepth) { return(new Vector3()); } // see if the ray hits anything. Intersection intersect = scene.Intersect(ray); if (intersect == null) { // We didn't hit anything. return the background. return(GetSkyColor(ray)); } // Draw some debug output. if (drawDebugLine) { Debugger.DrawDebugLine(ray.origin.X, ray.origin.Z, intersect.intersectionPoint.X, intersect.intersectionPoint.Z, Color.Green); } // Magic! if (absorb && intersect.GetMaterial().absorbtion.Length() > 0) { return(intersect.dist * -intersect.GetMaterial().absorbtion + DoFancyColorCalculations(ray, intersect, depth, drawDebugLine)); } else { return(DoFancyColorCalculations(ray, intersect, depth, drawDebugLine)); } }
public Color trace(Ray ray, int depth) { if (depth < 1) { return(new Color(Scene.Background.R, Scene.Background.G, Scene.Background.B)); } Intersection?possibleIntersection = Scene.Intersect(ray); if (!possibleIntersection.HasValue) { return(new Color(Scene.Background.R, Scene.Background.G, Scene.Background.B)); } Intersection intersection = possibleIntersection.Value; intersection.Tracer = this; if (depth == 4) { } Color result = intersection.Material.Ambient * Scene.Ambient; foreach (var light in Scene.Lights) { Vector lightDir = light.GetDirAt(intersection.Point); double lightPower = light.PowerAt(intersection.Point); Color lightColor = light.shade(intersection); Color current = new Color(); current += ShadingModels.LambertModel(intersection, lightDir) * intersection.Material.Lambert; current += ShadingModels.PhongModel(intersection, lightDir) * intersection.Material.Phong; current += ShadingModels.BlinnPhongModel(intersection, lightDir) * intersection.Material.BlinnPhong; current *= (lightColor * lightPower); result += current; } if (intersection.Material.Reflectance > 0) { result += intersection.Material.ReflectiveColor * intersection.Material.Reflectance * trace(new Ray( intersection.Point, Vector.Reflect( intersection.Ray.Direction, intersection.Normal) ), depth - 1); } if (intersection.Material.Refractivity > 0) { Vector?direction = Vector.Refract( intersection.Ray.Direction, intersection.Normal, intersection.Material.RefractivePower ); if (direction.HasValue) { result += intersection.Material.RefractiveColor * intersection.Material.Refractivity * trace(new Ray(intersection.Point, direction.Value), depth - 1); } } return(result); }
/// <summary> /// The core of the ray tracer. /// </summary> /// <param name="ray">The direction in which we look</param> /// <param name="recursionDepth">How far we can still go in recursion</param> /// <returns>The color associated with the ray</returns> private Vector3 CalculateColor(Ray ray, int recursionDepth = MAX_RECURSION) { if (recursionDepth-- <= 0) { return(Vector3.Zero); // recursion depth is reached } // Check for an intersection: Intersection intersection = scene.Intersect(ray); if (ray.debug) { // Debug if (recursionDepth == MAX_RECURSION - 1) { DrawRayDebug(ray, intersection, 0xff0000); // primary ray } else { DrawRayDebug(ray, intersection, 0x00ff00); // secondary, or higher ray } } Vector3 dir = ray.direction; if (intersection == null) { // The ray doesn't collide with any primitive, so return the color of the skybox int texx = Utils.scaleFloat((float)Math.Atan2(dir.Z, dir.X) / MathHelper.TwoPi + 0.5f, skybox.Height); int texy = (int)(Utils.SafeAcos(dir.Y) / Math.PI * (skybox.Height - 1)); return(skybox.Data[texx, texy]); } // Determine the diffuse and specular parts: Material mat = intersection.primitive.material; Vector3 ret = Vector3.Zero; if (mat.isSpecular) { // Calculate the reflection vector, and go one level deeper in the recursion Vector3 N = intersection.normal; // secondary ray, obtained by reflecting the current ray Ray ray2 = new Ray(intersection.location, dir - 2 * Vector3.Dot(dir, N) * N); // Pass on the same debug values: ray2.debug = ray.debug; ray2.debugSurface = ray.debugSurface; ray2.camerapos = ray.camerapos; ray2.debugxunit = ray.debugxunit; ray2.debugyunit = ray.debugyunit; // color at the intersection when looking in the reflection direction: Vector3 reflected = CalculateColor(ray2, recursionDepth); // multiply with the color of this material (in most cases this should be white for a realistic mirror) ret += mat.specularity * intersection.primitive.GetDiffuseColor(intersection) * reflected; } // Diffuse part: if (mat.isDiffuse) { foreach (Light light in scene.lights) { // The color is the sum of all the contributions Vector3 intensity = light.GetIntensity(ray, intersection, scene); ret += (1f - mat.specularity) * intensity; } } return(ret); }