/// <summary> /// Get diffuse color and specular for the hit point with a specific light /// </summary> /// <param name="light"></param> /// <param name="ray"></param> /// <param name="hit"></param> /// <param name="specular"></param> /// <param name="debug"></param> /// <returns></returns> protected Vector3 illuminateBy(Vector3 ppos, Light light, Ray ray, RayHit hit, ref Vector3 specular, bool debug) { // Calclulate if we are within light range var light_vec = ppos - hit.Position; float dist_sq = Vector3.Dot(light_vec, light_vec); float intens_sq = light.LightCache.IntensitySq; if (dist_sq >= intens_sq * Constants.LIGHT_DECAY) { return(Vector3.Zero); } // Create a shadow ray var dist = (float)Math.Sqrt(dist_sq); light_vec = light_vec / dist; var shadow_ray = new Ray(hit.Position + (light_vec * Constants.EPSILON), light_vec); var tmp = RayHit.Default(); foreach (var o in World.Objects) { if (o.Intersect(shadow_ray, ref tmp) && tmp.T < dist) { if (debug) { DebugData.ShadowRaysOccluded.Add(new Tuple <Ray, RayHit>(shadow_ray, tmp)); } return(new Vector3()); } } // Diffuse var materialColor = hit.Obj.Material.Texture == null ? hit.Obj.Material.Diffuse : hit.Obj.Material.Texture.GetColor(hit.Obj.GetUV(hit)); var color = materialColor * Math.Max(0.0f, Vector3.Dot(hit.Normal, light_vec)); // Inverse square law var light_powah = light.Intensity / (Constants.PI4 * dist_sq); light_powah *= light.AngleEnergy(light_vec.Normalized()); // Specular will be used separately if (hit.Obj.Material.IsGlossy) { var hardness = Math.Max(.0f, Vector3.Dot(-ray.Direction, QuickMaths.Reflect(-light_vec, hit.Normal))); specular += light.Colour * light_powah * hit.Obj.Material.Specular * (float)Math.Pow(hardness, hit.Obj.Material.Shinyness); } if (debug) { DebugData.ShadowRays.Add(new Tuple <Ray, Vector3>(shadow_ray, ppos)); } return(light.Colour * color * light_powah); }