Beispiel #1
0
        public bool build(Options options)
        {
            // read options
            maxDiffuseDepth    = options.getInt("depths.diffuse", maxDiffuseDepth);
            maxReflectionDepth = options.getInt("depths.reflection", maxReflectionDepth);
            maxRefractionDepth = options.getInt("depths.refraction", maxRefractionDepth);
            string giEngineType = options.getstring("gi.engine", null);

            giEngine = PluginRegistry.giEnginePlugins.createObject(giEngineType);
            string caustics = options.getstring("caustics", null);

            causticPhotonMap = PluginRegistry.causticPhotonMapPlugins.createObject(caustics);

            // validate options
            maxDiffuseDepth    = Math.Max(0, maxDiffuseDepth);
            maxReflectionDepth = Math.Max(0, maxReflectionDepth);
            maxRefractionDepth = Math.Max(0, maxRefractionDepth);

            SunflowSharp.Systems.Timer t = new SunflowSharp.Systems.Timer();
            t.start();
            // count total number of light samples
            int numLightSamples = 0;

            for (int i = 0; i < lights.Length; i++)
            {
                numLightSamples += lights[i].getNumSamples();
            }
            // initialize gi engine
            if (giEngine != null)
            {
                if (!giEngine.init(options, scene))
                {
                    return(false);
                }
            }

            if (!calculatePhotons(causticPhotonMap, "caustic", 0, options))
            {
                return(false);
            }
            t.end();

            UI.printInfo(UI.Module.LIGHT, "Light Server stats:");
            UI.printInfo(UI.Module.LIGHT, "  * Light sources found: {0}", lights.Length);
            UI.printInfo(UI.Module.LIGHT, "  * Light samples:       {0}", numLightSamples);
            UI.printInfo(UI.Module.LIGHT, "  * Max raytrace depth:");
            UI.printInfo(UI.Module.LIGHT, "      - Diffuse          {0}", maxDiffuseDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Reflection       {0}", maxReflectionDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Refraction       {0}", maxRefractionDepth);
            UI.printInfo(UI.Module.LIGHT, "  * GI engine            {0}", giEngineType == null ? "none" : giEngineType);
            UI.printInfo(UI.Module.LIGHT, "  * Caustics:            {0}", caustics == null ? "none" : caustics);
            UI.printInfo(UI.Module.LIGHT, "  * Shader override:     {0}", shaderOverride);
            UI.printInfo(UI.Module.LIGHT, "  * Photon override:     {0}", shaderOverridePhotons);
            UI.printInfo(UI.Module.LIGHT, "  * Build time:          {0}", t.ToString());
            return(true);
        }
Beispiel #2
0
        public bool build(Options options)
        {
            // read options
            maxDiffuseDepth = options.getInt("depths.diffuse", maxDiffuseDepth);
            maxReflectionDepth = options.getInt("depths.reflection", maxReflectionDepth);
            maxRefractionDepth = options.getInt("depths.refraction", maxRefractionDepth);
            string giEngineType = options.getstring("gi.engine", null);
            giEngine = PluginRegistry.giEnginePlugins.createObject(giEngineType);
            string caustics = options.getstring("caustics", null);
            causticPhotonMap = PluginRegistry.causticPhotonMapPlugins.createObject(caustics);

            // validate options
            maxDiffuseDepth = Math.Max(0, maxDiffuseDepth);
            maxReflectionDepth = Math.Max(0, maxReflectionDepth);
            maxRefractionDepth = Math.Max(0, maxRefractionDepth);

            SunflowSharp.Systems.Timer t = new SunflowSharp.Systems.Timer();
            t.start();
            // count total number of light samples
            int numLightSamples = 0;
            for (int i = 0; i < lights.Length; i++)
                numLightSamples += lights[i].getNumSamples();
            // initialize gi engine
            if (giEngine != null)
            {
                if (!giEngine.init(options, scene))
                    return false;
            }

            if (!calculatePhotons(causticPhotonMap, "caustic", 0, options))
                return false;
            t.end();

            UI.printInfo(UI.Module.LIGHT, "Light Server stats:");
            UI.printInfo(UI.Module.LIGHT, "  * Light sources found: {0}", lights.Length);
            UI.printInfo(UI.Module.LIGHT, "  * Light samples:       {0}", numLightSamples);
            UI.printInfo(UI.Module.LIGHT, "  * Max raytrace depth:");
            UI.printInfo(UI.Module.LIGHT, "      - Diffuse          {0}", maxDiffuseDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Reflection       {0}", maxReflectionDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Refraction       {0}", maxRefractionDepth);
            UI.printInfo(UI.Module.LIGHT, "  * GI engine            {0}", giEngineType == null ? "none" : giEngineType);
            UI.printInfo(UI.Module.LIGHT, "  * Caustics:            {0}", caustics == null ? "none" : caustics);
            UI.printInfo(UI.Module.LIGHT, "  * Shader override:     {0}", shaderOverride);
            UI.printInfo(UI.Module.LIGHT, "  * Photon override:     {0}", shaderOverridePhotons);
            UI.printInfo(UI.Module.LIGHT, "  * Build time:          {0}", t.ToString());
            return true;
        }
Beispiel #3
0
 public static GIEngine create(Options options)
 {
     string type = options.getstring("gi.engine", null);
     if (type == null || type == "null" || type == "none")
         return null;
     else if (type == "ambocc")
         return new AmbientOcclusionGIEngine(options);
     else if (type == "fake")
         return new FakeGIEngine(options);
     else if (type == "igi")
         return new InstantGI(options);
     else if (type == "irr-cache")
         return new IrradianceCacheGIEngine(options);
     else if (type == "path")
         return new PathTracingGIEngine(options);
     else
     {
         UI.printWarning(UI.Module.LIGHT, "Unrecognized GI engine type \"{0}\" - ignoring", type);
         return null;
     }
 }
 public IrradianceCacheGIEngine(Options options)
 {
     samples = options.getInt("gi.irr-cache.samples", 256);
     tolerance = options.getFloat("gi.irr-cache.tolerance", 0.05f);
     invTolerance = 1.0f / tolerance;
     minSpacing = options.getFloat("gi.irr-cache.min_spacing", 0.05f);
     maxSpacing = options.getFloat("gi.irr-cache.max_spacing", 5.00f);
     root = null;
     //rwl = new ReentrantReadWriteLock();
     globalPhotonMap = null;
     string gmap = options.getstring("gi.irr-cache.gmap", null);
     if (gmap == null || gmap == "none")
         return;
     int numEmit = options.getInt("gi.irr-cache.gmap.emit", 100000);
     int gather = options.getInt("gi.irr-cache.gmap.gather", 50);
     float radius = options.getFloat("gi.irr-cache.gmap.radius", 0.5f);
     if (gmap == "kd")
         globalPhotonMap = new GlobalPhotonMap(numEmit, gather, radius);
     else if (gmap == "grid")
         globalPhotonMap = new GridPhotonMap(numEmit, gather, radius);
     else
         UI.printWarning(UI.Module.LIGHT, "Unrecognized global photon map type \"%s\" - ignoring", gmap);
 }
Beispiel #5
0
        public bool build(Options options)
        {
            // read options
            maxDiffuseDepth    = options.getInt("depths.diffuse", maxDiffuseDepth);
            maxReflectionDepth = options.getInt("depths.reflection", maxReflectionDepth);
            maxRefractionDepth = options.getInt("depths.refraction", maxRefractionDepth);
            giEngine           = GIEngineFactory.create(options);
            string caustics = options.getstring("caustics", null);

            if (caustics == null || caustics == "none")
            {
                causticPhotonMap = null;
            }
            else if (caustics != null && caustics == "kd")
            {
                causticPhotonMap = new CausticPhotonMap(options);
            }
            else
            {
                UI.printWarning(UI.Module.LIGHT, "Unrecognized caustics photon map engine \"{0}\" - ignoring", caustics);
                causticPhotonMap = null;
            }

            // validate options
            maxDiffuseDepth    = Math.Max(0, maxDiffuseDepth);
            maxReflectionDepth = Math.Max(0, maxReflectionDepth);
            maxRefractionDepth = Math.Max(0, maxRefractionDepth);

            SunflowSharp.Systems.Timer t = new SunflowSharp.Systems.Timer();
            t.start();
            // count total number of light samples
            int numLightSamples = 0;

            for (int i = 0; i < lights.Length; i++)
            {
                numLightSamples += lights[i].getNumSamples();
            }
            // initialize gi engine
            if (giEngine != null)
            {
                if (!giEngine.init(scene))
                {
                    return(false);
                }
            }

            if (!calculatePhotons(causticPhotonMap, "caustic", 0))
            {
                return(false);
            }
            t.end();
            cacheLookups          = 0;
            cacheHits             = 0;
            cacheEmptyEntryMisses = 0;
            cacheWrongEntryMisses = 0;
            cacheEntryAdditions   = 0;
            if (_shadingCache != null)
            {
                // clear shading cache
                for (int i = 0; i < _shadingCache.Length; i++)
                {
                    _shadingCache[i] = null;
                }
            }
            UI.printInfo(UI.Module.LIGHT, "Light Server stats:");
            UI.printInfo(UI.Module.LIGHT, "  * Light sources found: {0}", lights.Length);
            UI.printInfo(UI.Module.LIGHT, "  * Light samples:       {0}", numLightSamples);
            UI.printInfo(UI.Module.LIGHT, "  * Max raytrace depth:");
            UI.printInfo(UI.Module.LIGHT, "      - Diffuse          {0}", maxDiffuseDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Reflection       {0}", maxReflectionDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Refraction       {0}", maxRefractionDepth);
            UI.printInfo(UI.Module.LIGHT, "  * GI engine            {0}", options.getstring("gi.engine", "none"));
            UI.printInfo(UI.Module.LIGHT, "  * Caustics:            {0}", caustics == null ? "none" : caustics);
            UI.printInfo(UI.Module.LIGHT, "  * Shader override:     {0}", shaderOverride);
            UI.printInfo(UI.Module.LIGHT, "  * Photon override:     {0}", shaderOverridePhotons);
            UI.printInfo(UI.Module.LIGHT, "  * Shading cache:       {0}", _shadingCache == null ? "off" : "on");
            UI.printInfo(UI.Module.LIGHT, "  * Build time:          {0}", t.ToString());
            return(true);
        }
Beispiel #6
0
        public bool prepare(Options options, Scene scene, int w, int h)
        {
            this.scene = scene;
            imageWidth = w;
            imageHeight = h;

            // fetch options
            bucketSize = options.getInt("bucket.size", bucketSize);
            bucketOrderName = options.getstring("bucket.order", bucketOrderName);
            minAADepth = options.getInt("aa.min", minAADepth);
            maxAADepth = options.getInt("aa.max", maxAADepth);
            superSampling = options.getInt("aa.samples", superSampling);
            displayAA = options.getbool("aa.display", displayAA);
            jitter = options.getbool("aa.jitter", jitter);
            contrastThreshold = options.getFloat("aa.contrast", contrastThreshold);

            // limit bucket size and compute number of buckets in each direction
            bucketSize = MathUtils.clamp(bucketSize, 16, 512);
            int numBucketsX = (imageWidth + bucketSize - 1) / bucketSize;
            int numBucketsY = (imageHeight + bucketSize - 1) / bucketSize;
            bucketOrder = BucketOrderFactory.create(bucketOrderName);
            bucketCoords = bucketOrder.getBucketSequence(numBucketsX, numBucketsY);
            // validate AA options
            minAADepth = MathUtils.clamp(minAADepth, -4, 5);
            maxAADepth = MathUtils.clamp(maxAADepth, minAADepth, 5);
            superSampling = MathUtils.clamp(superSampling, 1, 256);
            invSuperSampling = 1.0 / superSampling;
            // compute AA stepping sizes
            subPixelSize = (maxAADepth > 0) ? (1 << maxAADepth) : 1;
            minStepSize = maxAADepth >= 0 ? 1 : 1 << (-maxAADepth);
            if (minAADepth == maxAADepth)
                maxStepSize = minStepSize;
            else
                maxStepSize = minAADepth > 0 ? 1 << minAADepth : subPixelSize << (-minAADepth);
            useJitter = jitter && maxAADepth > 0;
            // compute anti-aliasing contrast thresholds
            contrastThreshold = MathUtils.clamp(contrastThreshold, 0, 1);
            thresh = contrastThreshold * (float)Math.Pow(2.0f, minAADepth);
            // read filter settings from scene
            filterName = options.getstring("filter", filterName);
			filter = PluginRegistry.filterPlugins.createObject(filterName);
            // adjust filter
            if (filter == null)
            {
                UI.printWarning(UI.Module.BCKT, "Unrecognized filter type: \"{0}\" - defaulting to box", filterName);
                filter = new BoxFilter();
                filterName = "box";
            }
            fhs = filter.getSize() * 0.5f;
            fs = (int)Math.Ceiling(subPixelSize * (fhs - 0.5f));

            // prepare QMC sampling
			sigmaOrder = Math.Min(QMC.MAX_SIGMA_ORDER, Math.Max(0, maxAADepth) + 13); // FIXME: how big should the table be?
			sigmaLength = 1 << sigmaOrder;
            UI.printInfo(UI.Module.BCKT, "Bucket renderer settings:");
            UI.printInfo(UI.Module.BCKT, "  * Resolution:         {0}x{1}", imageWidth, imageHeight);
            UI.printInfo(UI.Module.BCKT, "  * Bucket size:        {0}", bucketSize);
            UI.printInfo(UI.Module.BCKT, "  * Number of buckets:  {0}x{1}", numBucketsX, numBucketsY);
            if (minAADepth != maxAADepth)
                UI.printInfo(UI.Module.BCKT, "  * Anti-aliasing:      {0} -> {1} (adaptive)", aaDepthTostring(minAADepth), aaDepthTostring(maxAADepth));
            else
                UI.printInfo(UI.Module.BCKT, "  * Anti-aliasing:      {0} (fixed)", aaDepthTostring(minAADepth));
            UI.printInfo(UI.Module.BCKT, "  * Rays per sample:    {0}", superSampling);
            UI.printInfo(UI.Module.BCKT, "  * Subpixel jitter:    {0}", useJitter ? "on" : (jitter ? "auto-off" : "off"));
            UI.printInfo(UI.Module.BCKT, "  * Contrast threshold: {0}", contrastThreshold);
            UI.printInfo(UI.Module.BCKT, "  * Filter type:        {0}", filterName);
            UI.printInfo(UI.Module.BCKT, "  * Filter size:        {0} pixels", filter.getSize());
            return true;
        }
Beispiel #7
0
        public bool build(Options options)
        {
            // read options
            maxDiffuseDepth = options.getInt("depths.diffuse", maxDiffuseDepth);
            maxReflectionDepth = options.getInt("depths.reflection", maxReflectionDepth);
            maxRefractionDepth = options.getInt("depths.refraction", maxRefractionDepth);
            giEngine = GIEngineFactory.create(options);
            string caustics = options.getstring("caustics", null);
            if (caustics == null || caustics == "none")
                causticPhotonMap = null;
            else if (caustics != null && caustics == "kd")
                causticPhotonMap = new CausticPhotonMap(options);
            else
            {
                UI.printWarning(UI.Module.LIGHT, "Unrecognized caustics photon map engine \"{0}\" - ignoring", caustics);
                causticPhotonMap = null;
            }

            // validate options
            maxDiffuseDepth = Math.Max(0, maxDiffuseDepth);
            maxReflectionDepth = Math.Max(0, maxReflectionDepth);
            maxRefractionDepth = Math.Max(0, maxRefractionDepth);

            SunflowSharp.Systems.Timer t = new SunflowSharp.Systems.Timer();
            t.start();
            // count total number of light samples
            int numLightSamples = 0;
            for (int i = 0; i < lights.Length; i++)
                numLightSamples += lights[i].getNumSamples();
            // initialize gi engine
            if (giEngine != null)
            {
                if (!giEngine.init(scene))
                    return false;
            }

            if (!calculatePhotons(causticPhotonMap, "caustic", 0))
                return false;
            t.end();
            cacheLookups = 0;
            cacheHits = 0;
            cacheEmptyEntryMisses = 0;
            cacheWrongEntryMisses = 0;
            cacheEntryAdditions = 0;
            if (_shadingCache != null)
            {
                // clear shading cache
                for (int i = 0; i < _shadingCache.Length; i++)
                    _shadingCache[i] = null;
            }
            UI.printInfo(UI.Module.LIGHT, "Light Server stats:");
            UI.printInfo(UI.Module.LIGHT, "  * Light sources found: {0}", lights.Length);
            UI.printInfo(UI.Module.LIGHT, "  * Light samples:       {0}", numLightSamples);
            UI.printInfo(UI.Module.LIGHT, "  * Max raytrace depth:");
            UI.printInfo(UI.Module.LIGHT, "      - Diffuse          {0}", maxDiffuseDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Reflection       {0}", maxReflectionDepth);
            UI.printInfo(UI.Module.LIGHT, "      - Refraction       {0}", maxRefractionDepth);
            UI.printInfo(UI.Module.LIGHT, "  * GI engine            {0}", options.getstring("gi.engine", "none"));
            UI.printInfo(UI.Module.LIGHT, "  * Caustics:            {0}", caustics == null ? "none" : caustics);
            UI.printInfo(UI.Module.LIGHT, "  * Shader override:     {0}", shaderOverride);
            UI.printInfo(UI.Module.LIGHT, "  * Photon override:     {0}", shaderOverridePhotons);
            UI.printInfo(UI.Module.LIGHT, "  * Shading cache:       {0}", _shadingCache == null ? "off" : "on");
            UI.printInfo(UI.Module.LIGHT, "  * Build time:          {0}", t.ToString());
            return true;
        }
Beispiel #8
0
        /**
         * Render the scene using the specified options, image sampler and display.
         *
         * @param options rendering options object
         * @param sampler image sampler
         * @param display display to send the image to, a default display will
         *            be created if <code>null</code>
         */
        public void render(Options options, ImageSampler sampler, IDisplay display)
        {
            if (display == null)
                display = null;// new FrameDisplay();

            if (bakingInstance != null)
            {
                UI.printDetailed(UI.Module.SCENE, "Creating primitives for lightmapping ...");
                bakingPrimitives = bakingInstance.getBakingPrimitives();
                if (bakingPrimitives == null)
                {
                    UI.printError(UI.Module.SCENE, "Lightmap baking is not supported for the given instance.");
                    return;
                }
                int n = bakingPrimitives.getNumPrimitives();
                UI.printInfo(UI.Module.SCENE, "Building acceleration structure for lightmapping ({0} num primitives) ...", n);
                bakingAccel = AccelerationStructureFactory.create("auto", n, true);
                bakingAccel.build(bakingPrimitives);
            }
            else
            {
                bakingPrimitives = null;
                bakingAccel = null;
            }
            bakingViewDependent = options.getbool("baking.viewdep", bakingViewDependent);

            if ((bakingInstance != null && bakingViewDependent && camera == null) || (bakingInstance == null && camera == null))
            {
                UI.printError(UI.Module.SCENE, "No camera found");
                return;
            }

            // read from options
            threads = options.getInt("threads", 0);
            lowPriority = options.getbool("threads.lowPriority", true);
            imageWidth = options.getInt("resolutionX", 640);
            imageHeight = options.getInt("resolutionY", 480);
            // limit resolution to 16k
            imageWidth = MathUtils.clamp(imageWidth, 1, 1 << 14);
            imageHeight = MathUtils.clamp(imageHeight, 1, 1 << 14);

            // get acceleration structure info
            // count scene primitives
            long numPrimitives = 0;
            for (int i = 0; i < instanceList.getNumPrimitives(); i++)
                numPrimitives += instanceList.getNumPrimitives(i);
            UI.printInfo(UI.Module.SCENE, "Scene stats:");
            UI.printInfo(UI.Module.SCENE, "  * Infinite instances:  {0}", infiniteInstanceList.getNumPrimitives());
            UI.printInfo(UI.Module.SCENE, "  * Instances:           {0}", instanceList.getNumPrimitives());
            UI.printInfo(UI.Module.SCENE, "  * Primitives:          {0}", numPrimitives);
            string accelName = options.getstring("accel", null);
            if (accelName != null)
            {
                rebuildAccel = rebuildAccel || acceltype != accelName;
                acceltype = accelName;
            }
            UI.printInfo(UI.Module.SCENE, "  * Instance accel:      {0}", acceltype);
            if (rebuildAccel)
            {
                intAccel = AccelerationStructureFactory.create(acceltype, instanceList.getNumPrimitives(), false);
                intAccel.build(instanceList);
                rebuildAccel = false;
            }
            UI.printInfo(UI.Module.SCENE, "  * Scene bounds:        {0}", getBounds());
            UI.printInfo(UI.Module.SCENE, "  * Scene center:        {0}", getBounds().getCenter());
            UI.printInfo(UI.Module.SCENE, "  * Scene diameter:      {0}", getBounds().getExtents().Length());
            UI.printInfo(UI.Module.SCENE, "  * Lightmap bake:       {0}", bakingInstance != null ? (bakingViewDependent ? "view" : "ortho") : "off");
            if (sampler == null)
                return;
            if (!lightServer.build(options))
                return;
            // render
            UI.printInfo(UI.Module.SCENE, "Rendering ...");
            sampler.prepare(options, this, imageWidth, imageHeight);
            sampler.render(display);
            lightServer.showStats();
            // discard baking tesselation/accel structure
            bakingPrimitives = null;
            bakingAccel = null;
            UI.printInfo(UI.Module.SCENE, "Done.");
        }
Beispiel #9
0
        /**
         * Render the scene using the specified options, image sampler and display.
         *
         * @param options rendering options object
         * @param sampler image sampler
         * @param display display to send the image to, a default display will
         *            be created if <code>null</code>
         */
        public void render(Options options, ImageSampler sampler, IDisplay display)
        {
            stats.reset();
            if (display == null)
            {
                display = null;// new FrameDisplay();
            }
            if (bakingInstance != null)
            {
                UI.printDetailed(UI.Module.SCENE, "Creating primitives for lightmapping ...");
                bakingPrimitives = bakingInstance.getBakingPrimitives();
                if (bakingPrimitives == null)
                {
                    UI.printError(UI.Module.SCENE, "Lightmap baking is not supported for the given instance.");
                    return;
                }
                int n = bakingPrimitives.getNumPrimitives();
                UI.printInfo(UI.Module.SCENE, "Building acceleration structure for lightmapping ({0} num primitives) ...", n);
                bakingAccel = AccelerationStructureFactory.create("auto", n, true);
                bakingAccel.build(bakingPrimitives);
            }
            else
            {
                bakingPrimitives = null;
                bakingAccel      = null;
            }
            bakingViewDependent = options.getbool("baking.viewdep", bakingViewDependent);

            if ((bakingInstance != null && bakingViewDependent && camera == null) || (bakingInstance == null && camera == null))
            {
                UI.printError(UI.Module.SCENE, "No camera found");
                return;
            }

            // read from options
            threads     = options.getInt("threads", 0);
            lowPriority = options.getbool("threads.lowPriority", true);
            imageWidth  = options.getInt("resolutionX", 640);
            imageHeight = options.getInt("resolutionY", 480);
            // limit resolution to 16k
            imageWidth  = MathUtils.clamp(imageWidth, 1, 1 << 14);
            imageHeight = MathUtils.clamp(imageHeight, 1, 1 << 14);

            // prepare lights
            createAreaLightInstances();

            // get acceleration structure info
            // count scene primitives
            long numPrimitives = 0;

            for (int i = 0; i < instanceList.getNumPrimitives(); i++)
            {
                numPrimitives += instanceList.getNumPrimitives(i);
            }
            UI.printInfo(UI.Module.SCENE, "Scene stats:");
            UI.printInfo(UI.Module.SCENE, "  * Infinite instances:  {0}", infiniteInstanceList.getNumPrimitives());
            UI.printInfo(UI.Module.SCENE, "  * Instances:           {0}", instanceList.getNumPrimitives());
            UI.printInfo(UI.Module.SCENE, "  * Primitives:          {0}", numPrimitives);
            string accelName = options.getstring("accel", null);

            if (accelName != null)
            {
                rebuildAccel = rebuildAccel || acceltype != accelName;
                acceltype    = accelName;
            }
            UI.printInfo(UI.Module.SCENE, "  * Instance accel:      {0}", acceltype);
            if (rebuildAccel)
            {
                intAccel = AccelerationStructureFactory.create(acceltype, instanceList.getNumPrimitives(), false);
                intAccel.build(instanceList);
                rebuildAccel = false;
            }
            UI.printInfo(UI.Module.SCENE, "  * Scene bounds:        {0}", getBounds());
            UI.printInfo(UI.Module.SCENE, "  * Scene center:        {0}", getBounds().getCenter());
            UI.printInfo(UI.Module.SCENE, "  * Scene diameter:      {0}", getBounds().getExtents().Length());
            UI.printInfo(UI.Module.SCENE, "  * Lightmap bake:       {0}", bakingInstance != null ? (bakingViewDependent ? "view" : "ortho") : "off");
            if (sampler == null)
            {
                return;
            }
            if (!lightServer.build(options))
            {
                return;
            }
            // render
            UI.printInfo(UI.Module.SCENE, "Rendering ...");
            stats.setResolution(imageWidth, imageHeight);
            sampler.prepare(options, this, imageWidth, imageHeight);
            sampler.render(display);
            // show statistics
            stats.displayStats();
            lightServer.showStats();
            // discard area lights
            removeAreaLightInstances();

            // discard baking tesselation/accel structure
            bakingPrimitives = null;
            bakingAccel      = null;
            UI.printInfo(UI.Module.SCENE, "Done.");
        }