Ejemplo n.º 1
0
        /// <summary>
        /// Traces the ray if its inside an object which means its probably in refraction loop
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="obj"></param>
        /// <param name="debug"></param>
        /// <returns></returns>
        protected Vector3 traceRayInside(Ray ray, Primitive obj, bool debug)
        {
            if (ray.isOutside())
            {
                return(TraceRay(ray, debug));                 // Should not happen anyway
            }
            Vector3 ret             = Vector3.Zero;
            float   multiplier      = 1;
            float   absorb_distance = 0;

            // Do the refraction loop. Aka refract, reflect, repeat
            RayHit hit = RayHit.Default();

            while (ray.Depth < Settings.MaxDepth - 1 && multiplier > Constants.EPSILON)
            {
                if (!obj.Intersect(ray, ref hit))
                {
                    return(ret);                              // Should not happen either
                }
                if (debug)
                {
                    DebugData.RefractRays.Add(new Tuple <Ray, RayHit>(ray, hit));
                }

                // Beer absorption
                absorb_distance += hit.T;
                var absorb = QuickMaths.Exp(-obj.Material.Absorb * absorb_distance);

                // Fresnel
                var reflect_multiplier = QuickMaths.Fresnel(obj.Material.RefractionIndex, Constants.LIGHT_IOR, ray.Direction, hit.Normal);
                var refract_multiplier = 1f - reflect_multiplier;

                // refract if its worth
                if (refract_multiplier > Constants.EPSILON)
                {
                    ret += TraceRay(RayTrans.Refract(ray, hit), debug) * refract_multiplier * multiplier * absorb;
                }

                ray         = RayTrans.Reflect(ray, hit);
                multiplier *= reflect_multiplier;
            }

            return(ret);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Trace the ray and go around the world in 80ns. Or more :S
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="debug"></param>
        /// <returns></returns>
        public Vector3 TraceRay(Ray ray, bool debug = false)
        {
            Vector3 ret = Vector3.Zero;

            if (ray.Depth > Settings.MaxDepth)
            {
                return(ret);
            }

            // Check for intersections
            RayHit hit = intersect(ray);

            if (hit.Obj == null)
            {
                return(World.Environent == null ? Vector3.Zero : World.Environent.GetColor(ray));
            }
            if (debug)
            {
                DebugData.PrimaryRays.Add(new Tuple <Ray, RayHit>(ray, hit));
            }

            // Calculate color and specular highlights. Pure mirrors dont have diffuse
            Vector3 specular = Vector3.Zero;
            Vector3 color    = Vector3.Zero;

            if (!hit.Obj.Material.IsMirror)
            {
                color += illuminate(ray, hit, ref specular, debug);
                color += World.Environent.AmbientLight;
            }


            // Different materials are handled differently. Would be cool to move that into material
            if (hit.Obj.Material.IsMirror)
            {
                ret = TraceRay(RayTrans.Reflect(ray, hit), debug);
            }
            else if (hit.Obj.Material.IsDielectic)
            {
                var   n1 = ray.isOutside() ? Constants.LIGHT_IOR : hit.Obj.Material.RefractionIndex; // TODO: shorten this shizzle into a func
                var   n2 = ray.isOutside() ? hit.Obj.Material.RefractionIndex : Constants.LIGHT_IOR;
                float reflect_multiplier = QuickMaths.Fresnel(n1, n2, hit.Normal, ray.Direction);
                reflect_multiplier = hit.Obj.Material.Reflectivity + (1f - hit.Obj.Material.Reflectivity) * reflect_multiplier;
                float transmission_multiplier = 1 - reflect_multiplier;

                // Reflect if its worth it
                if (reflect_multiplier > Constants.EPSILON)
                {
                    Ray  reflRay     = RayTrans.Reflect(ray, hit);
                    uint takeSamples = 0;
                    if (hit.Obj.Material.Roughness > 0.001f && ray.Refldepth <= 1)
                    {
                        takeSamples = Settings.MaxReflectionSamples;
                    }
                    else
                    {
                        takeSamples = 1;
                    }
                    //Take many samples for rough reflections
                    for (int i = 0; i < takeSamples; i++)
                    {
                        Ray localRay = reflRay;
                        localRay.Direction = RRandom.RandomChange(reflRay.Direction, hit.Obj.Material.Roughness);
                        ret += reflect_multiplier * TraceRay(localRay, debug);
                    }
                    ret /= takeSamples;
                }
                if (transmission_multiplier > Constants.EPSILON)
                {
                    if (hit.Obj.Material.IsRefractive)
                    {
                        var tmp_ray = RayTrans.Refract(ray, hit);
                        if (!float.IsNaN(tmp_ray.Direction.X)) // Happens rarely
                        {
                            ret += transmission_multiplier * traceRayInside(tmp_ray, hit.Obj, debug);
                        }
                    }
                    else
                    {
                        ret += transmission_multiplier * color;
                    }
                }
            }
            else
            {
                // Standard diffuse
                ret = color;
            }

            return(ret + specular);
        }