/// <summary>
        /// Recursive shading function - computes color contribution of the given ray (shot from the
        /// origin 'p0' into direction vector 'p1''). Recursion is stopped
        /// by a hybrid method: 'importance' and 'level' are checked.
        /// Internal integration support.
        /// </summary>
        /// <param name="level">Current recursion depth.</param>
        /// <param name="importance">Importance of the current ray.</param>
        /// <param name="p0">Ray origin.</param>
        /// <param name="p1">Ray direction vector.</param>
        /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
        /// <param name="total">Total number of samples (for integration).</param>
        /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
        /// <param name="color">Result color.</param>
        /// <returns>Hash-value (ray sub-signature) used for adaptive subsampling.</returns>
        protected virtual long shade(int level, double importance, ref Vector3d p0, ref Vector3d p1,
                                     int rank, int total, RandomJames rnd, double[] color)
        {
            int bands = color.Length;
            LinkedList <Intersection> intersections = scene.Intersectable.Intersect(p0, p1);

            Intersection.countRays++;
            Intersection i = Intersection.FirstIntersection(intersections, ref p1);
            int          b;

            if (i == null)      // no intersection -> background color
            {
                Array.Copy(scene.BackgroundColor, color, bands);
                return(1L);
            }

            // there was at least one intersection
            i.Complete();

            // hash code for adaptive supersampling:
            long hash = i.Solid.GetHashCode();

            // apply all the textures fist..
            if (i.Textures != null)
            {
                foreach (ITexture tex in i.Textures)
                {
                    hash = hash * HASH_TEXTURE + tex.Apply(i, rank, total, rnd);
                }
            }

            p1 = -p1; // viewing vector
            p1.Normalize();

            if (scene.Sources == null || scene.Sources.Count < 1)
            {
                // no light sources at all
                Array.Copy(i.SurfaceColor, color, bands);
            }
            else
            {
                // apply the reflectance model for each source
                i.Material       = (IMaterial)i.Material.Clone();
                i.Material.Color = i.SurfaceColor;
                Array.Clear(color, 0, bands);

                foreach (ILightSource source in scene.Sources)
                {
                    Vector3d dir;
                    double[] intensity = source.GetIntensity(i, rank, total, rnd, out dir);
                    if (intensity != null)
                    {
                        if (DoShadows && !dir.Equals(Vector3d.Zero))
                        {
                            intersections = scene.Intersectable.Intersect(i.CoordWorld, dir);
                            Intersection.countRays++;
                            Intersection si = Intersection.FirstIntersection(intersections, ref dir);
                            // Better shadow testing: intersection between 0.0 and 1.0 kills the lighting
                            if (si != null && !si.Far(1.0, ref dir))
                            {
                                continue;
                            }
                        }

                        double[] reflection = i.ReflectanceModel.ColorReflection(i, dir, p1, ReflectionComponent.ALL);
                        if (reflection != null)
                        {
                            for (b = 0; b < bands; b++)
                            {
                                color[b] += intensity[b] * reflection[b];
                            }
                            hash = hash * HASH_LIGHT + source.GetHashCode();
                        }
                    }
                }
            }

            // check the recursion depth:
            if (level++ >= MaxLevel ||
                !DoReflections && !DoRefractions)
            {
                return(hash);               // no further recursion
            }
            Vector3d r;
            double   maxK;

            double[] comp = new double[bands];
            double   newImportance;

            if (DoReflections)              // trying to shoot a reflected ray..
            {
                Geometry.SpecularReflection(ref i.Normal, ref p1, out r);
                double[] ks = i.ReflectanceModel.ColorReflection(i, p1, r, ReflectionComponent.SPECULAR_REFLECTION);
                if (ks != null)
                {
                    maxK = ks[0];
                    for (b = 1; b < bands; b++)
                    {
                        if (ks[b] > maxK)
                        {
                            maxK = ks[b];
                        }
                    }

                    newImportance = importance * maxK;
                    if (newImportance >= MinImportance) // do compute the reflected ray
                    {
                        hash += HASH_REFLECT * shade(level, newImportance, ref i.CoordWorld, ref r, rank, total, rnd, comp);
                        for (b = 0; b < bands; b++)
                        {
                            color[b] += ks[b] * comp[b];
                        }
                    }
                }
            }

            if (DoRefractions)                 // trying to shoot a refracted ray..
            {
                maxK          = i.Material.Kt; // simple solution, no influence of reflectance model yet
                newImportance = importance * maxK;
                if (newImportance < MinImportance)
                {
                    return(hash);
                }

                // refracted ray:
                if ((r = Geometry.SpecularRefraction(i.Normal, i.Material.n, p1)) == null)
                {
                    return(hash);
                }

                hash += HASH_REFRACT * shade(level, newImportance, ref i.CoordWorld, ref r, rank, total, rnd, comp);
                for (b = 0; b < bands; b++)
                {
                    color[b] += maxK * comp[b];
                }
            }

            return(hash);
        }
Beispiel #2
0
        /// <summary>
        /// Computes one image sample. Internal integration support.
        /// </summary>
        /// <param name="x">Horizontal coordinate.</param>
        /// <param name="y">Vertical coordinate.</param>
        /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
        /// <param name="total">Total number of samples (for integration).</param>
        /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
        /// <param name="color">Computed sample color.</param>
        /// <returns>Hash-value used for adaptive subsampling.</returns>
        public virtual long GetSample(double x, double y, int rank, int total, RandomJames rnd, double[] color)
        {
            Vector3d p0, p1;
            int      bands = color.Length;

            if (!scene.Camera.GetRay(x, y, rank, total, rnd, out p0, out p1))
            {
                Array.Clear(color, 0, bands);              // invalid ray -> black color
                return(1L);
            }

            LinkedList <Intersection> intersections = scene.Intersectable.Intersect(p0, p1);

            Intersection.countRays++;
            Intersection i = Intersection.FirstIntersection(intersections, ref p1);

            if (i == null)        // no intersection -> background color
            {
                Array.Copy(scene.BackgroundColor, color, bands);
                return(0L);
            }

            // there was at least one intersection
            i.Complete();

            // hash code for adaptive supersampling:
            long hash = i.Solid.GetHashCode();

            // apply all the textures fist..
            if (i.Textures != null)
            {
                foreach (ITexture tex in i.Textures)
                {
                    hash = hash * HASH_TEXTURE + tex.Apply(i, rank, total, rnd);
                }
            }

            // terminate if light sources are missing
            if (scene.Sources == null || scene.Sources.Count < 1)
            {
                Array.Copy(i.SurfaceColor, color, bands);
                return(hash);
            }

            // .. else apply the reflectance model for each source
            p1 = -p1;
            p1.Normalize();

            i.Material       = (IMaterial)i.Material.Clone();
            i.Material.Color = i.SurfaceColor;
            Array.Clear(color, 0, bands);

            foreach (ILightSource source in scene.Sources)
            {
                Vector3d dir;
                double[] intensity = source.GetIntensity(i, rank, total, rnd, out dir);
                if (intensity != null)
                {
                    double[] reflection = i.ReflectanceModel.ColorReflection(i, dir, p1, ReflectionComponent.ALL);
                    if (reflection != null)
                    {
                        for (int b = 0; b < bands; b++)
                        {
                            color[b] += intensity[b] * reflection[b];
                        }
                        hash = hash * HASH_LIGHT + source.GetHashCode();
                    }
                }
            }

            return(hash);
        }
Beispiel #3
0
        /// <summary>
        /// Recursive shading function - computes color contribution of the given ray (shot from the
        /// origin 'p0' into direction vector 'p1''). Recursion is stopped
        /// by a hybrid method: 'importance' and 'level' are checked.
        /// Internal integration support.
        /// </summary>
        /// <param name="level">Current recursion depth.</param>
        /// <param name="importance">Importance of the current ray.</param>
        /// <param name="p0">Ray origin.</param>
        /// <param name="p1">Ray direction vector.</param>
        /// <param name="color">Result color.</param>
        /// <returns>Hash-value (ray sub-signature) used for adaptive subsampling.</returns>
        protected virtual long shade(int level,
                                     double importance,
                                     ref Vector3d p0,
                                     ref Vector3d p1,
                                     double[] color)
        {
            Vector3d direction = p1;

            int bands = color.Length;
            LinkedList <Intersection> intersections = scene.Intersectable.Intersect(p0, p1);

            // If the ray is primary, increment both counters
            Statistics.IncrementRaysCounters(1, level == 0);

            Intersection i = Intersection.FirstIntersection(intersections, ref p1);
            int          b;

            if (i == null)
            {
                // No intersection -> background color
                rayRegisterer?.RegisterRay(AbstractRayRegisterer.RayType.rayVisualizerNormal, level, p0, direction * 100000);

                return(scene.Background.GetColor(p1, color));
            }

            // There was at least one intersection
            i.Complete();

            rayRegisterer?.RegisterRay(AbstractRayRegisterer.RayType.unknown, level, p0, i);

            // Hash code for adaptive supersampling
            long hash = i.Solid.GetHashCode();

            // Apply all the textures first
            if (i.Textures != null)
            {
                foreach (ITexture tex in i.Textures)
                {
                    hash = hash * HASH_TEXTURE + tex.Apply(i);
                }
            }

            if (MT.pointCloudCheckBox && !MT.pointCloudSavingInProgress && !MT.singleRayTracing)
            {
                foreach (Intersection intersection in intersections)
                {
                    if (!intersection.completed)
                    {
                        intersection.Complete();
                    }

                    if (intersection.Textures != null && !intersection.textureApplied)
                    {
                        foreach (ITexture tex in intersection.Textures)
                        {
                            tex.Apply(intersection);
                        }
                    }

                    double[] vertexColor = new double[3];
                    Util.ColorCopy(intersection.SurfaceColor, vertexColor);
                    Master.singleton?.pointCloud?.AddToPointCloud(intersection.CoordWorld, vertexColor, intersection.Normal, MT.threadID);
                }
            }

            p1 = -p1; // viewing vector
            p1.Normalize();

            // !!! TODO: optional light-source processing (controlled by an attribute?) !!!

            if (scene.Sources == null || scene.Sources.Count < 1)
            {
                // No light sources at all.
                Util.ColorCopy(i.SurfaceColor, color);
            }
            else
            {
                // Apply the reflectance model for each source.
                i.Material       = (IMaterial)i.Material.Clone();
                i.Material.Color = i.SurfaceColor;
                Array.Clear(color, 0, bands);

                foreach (ILightSource source in scene.Sources)
                {
                    double[] intensity = source.GetIntensity(i, out Vector3d dir);

                    if (MT.singleRayTracing && source.position != null)
                    {
                        // Register shadow ray for RayVisualizer.
                        rayRegisterer?.RegisterRay(AbstractRayRegisterer.RayType.rayVisualizerShadow, i.CoordWorld, (Vector3d)source.position);
                    }

                    if (intensity != null)
                    {
                        if (DoShadows && dir != Vector3d.Zero)
                        {
                            intersections = scene.Intersectable.Intersect(i.CoordWorld, dir);
                            Statistics.allRaysCount++;
                            Intersection si = Intersection.FirstIntersection(intersections, ref dir);
                            // Better shadow testing: intersection between 0.0 and 1.0 kills the lighting.
                            if (si != null && !si.Far(1.0, ref dir))
                            {
                                continue;
                            }
                        }

                        double[] reflection = i.ReflectanceModel.ColorReflection(i, dir, p1, ReflectionComponent.ALL);
                        if (reflection != null)
                        {
                            for (b = 0; b < bands; b++)
                            {
                                color[b] += intensity[b] * reflection[b];
                            }
                            hash = hash * HASH_LIGHT + source.GetHashCode();
                        }
                    }
                }
            }

            // Check the recursion depth.
            if (level++ >= MaxLevel || !DoReflections && !DoRefractions)
            {
                // No further recursion.
                return(hash);
            }

            Vector3d r;
            double   maxK;

            double[] comp = new double[bands];
            double   newImportance;

            // !!! TODO: alternative intersection handling, different from reflection + refraction !!!
            // Controlled by an attribute (containing a callback-function)?

            if (DoReflections)
            {
                // Shooting a reflected ray.
                Geometry.SpecularReflection(ref i.Normal, ref p1, out r);
                double[] ks = i.ReflectanceModel.ColorReflection(i, p1, r, ReflectionComponent.SPECULAR_REFLECTION);
                if (ks != null)
                {
                    maxK = ks[0];
                    for (b = 1; b < bands; b++)
                    {
                        if (ks[b] > maxK)
                        {
                            maxK = ks[b];
                        }
                    }

                    newImportance = importance * maxK;
                    if (newImportance >= MinImportance)
                    {
                        // Do compute the reflected ray.
                        hash += HASH_REFLECT * shade(level, newImportance, ref i.CoordWorld, ref r, comp);
                        for (b = 0; b < bands; b++)
                        {
                            color[b] += ks[b] * comp[b];
                        }
                    }
                }
            }

            if (DoRefractions)
            {
                // Shooting a refracted ray.
                maxK          = i.Material.Kt; // simple solution - no influence of reflectance model yet
                newImportance = importance * maxK;
                if (newImportance < MinImportance)
                {
                    return(hash);
                }

                // Refracted ray.
                if ((r = Geometry.SpecularRefraction(i.Normal, i.Material.n, p1)) == Vector3d.Zero)
                {
                    return(hash);
                }

                hash += HASH_REFRACT * shade(level, newImportance, ref i.CoordWorld, ref r, comp);
                for (b = 0; b < bands; b++)
                {
                    color[b] += maxK * comp[b];
                }
            }

            return(hash);
        }