예제 #1
0
        private void generateFixedSamples(Vector3[] samples, Color[] colors)
        {
            for (int i = 0; i < samples.Length; i++)
            {
                double randX = (double)i / (double)samples.Length;
                double randY = QMC.halton(0, i);
                int    x     = 0;
                while (randX >= colHistogram[x] && x < colHistogram.Length - 1)
                {
                    x++;
                }
                float[] rowHistogram = imageHistogram[x];
                int     y            = 0;
                while (randY >= rowHistogram[y] && y < rowHistogram.Length - 1)
                {
                    y++;
                }
                // sample from (x, y)
                float u = (float)((x == 0) ? (randX / colHistogram[0]) : ((randX - colHistogram[x - 1]) / (colHistogram[x] - colHistogram[x - 1])));
                float v = (float)((y == 0) ? (randY / rowHistogram[0]) : ((randY - rowHistogram[y - 1]) / (rowHistogram[y] - rowHistogram[y - 1])));

                float px = ((x == 0) ? colHistogram[0] : (colHistogram[x] - colHistogram[x - 1]));
                float py = ((y == 0) ? rowHistogram[0] : (rowHistogram[y] - rowHistogram[y - 1]));

                float su = (x + u) / colHistogram.Length;
                float sv = (y + v) / rowHistogram.Length;

                float invP = (float)Math.Sin(sv * Math.PI) * jacobian / (numSamples * px * py);
                samples[i] = getDirection(su, sv);
                basis.transform(samples[i]);
                colors[i] = texture.getPixel(su, sv).mul(invP);
            }
        }
예제 #2
0
 private ShadingState(ShadingState previous, IntersectionState istate, Ray r, int i, int d)
 {
     this.r           = r;
     this.istate      = istate;
     this.i           = i;
     this.d           = d;
     this.instance    = istate.instance; // local copy
     this.primitiveID = istate.id;
     this.hitU        = istate.u;
     this.hitV        = istate.v;
     if (previous == null)
     {
         diffuseDepth    = 0;
         reflectionDepth = 0;
         refractionDepth = 0;
     }
     else
     {
         diffuseDepth    = previous.diffuseDepth;
         reflectionDepth = previous.reflectionDepth;
         refractionDepth = previous.refractionDepth;
         this.server     = previous.server;
         this.map        = previous.map;
         this.rx         = previous.rx;
         this.ry         = previous.ry;
         this.i         += previous.i;
         this.d         += previous.d;
     }
     behind        = false;
     cosND         = float.NaN;
     includeLights = includeSpecular = true;
     qmcD0I        = QMC.halton(this.d, this.i);
     qmcD1I        = QMC.halton(this.d + 1, this.i);
     result        = null;
 }
예제 #3
0
        private int progressiveRenderNext(IntersectionState istate)
        {
            int         TASK_SIZE = 16;
            SmallBucket first     = smallBucketQueue.Count > 0 ? smallBucketQueue.Dequeue() : null;

            if (first == null)
            {
                return(0);
            }
            int  ds      = first.size / TASK_SIZE;
            bool useMask = smallBucketQueue.Count != 0;
            int  mask    = 2 * first.size / TASK_SIZE - 1;
            int  pixels  = 0;

            for (int i = 0, y = first.y; i < TASK_SIZE && y < imageHeight; i++, y += ds)
            {
                for (int j = 0, x = first.x; j < TASK_SIZE && x < imageWidth; j++, x += ds)
                {
                    // check to see if this is a pixel from a higher level tile
                    if (useMask && (x & mask) == 0 && (y & mask) == 0)
                    {
                        continue;
                    }
                    int          instance = (x & (sigma.Length - 1)) * sigma.Length + sigma[y & (sigma.Length - 1)];
                    double       time     = QMC.halton(1, instance);
                    double       lensU    = QMC.halton(2, instance);
                    double       lensV    = QMC.halton(3, instance);
                    ShadingState state    = scene.getRadiance(istate, x, imageHeight - 1 - y, lensU, lensV, time, instance);
                    Color        c        = state != null?state.getResult() : Color.BLACK;

                    pixels++;
                    // fill region
                    display.imageFill(x, y, Math.Min(ds, imageWidth - x), Math.Min(ds, imageHeight - y), c);
                }
            }
            if (first.size >= 2 * TASK_SIZE)
            {
                // generate child buckets
                int size = (int)((uint)first.size >> 1);//>>>
                for (int i = 0; i < 2; i++)
                {
                    if (first.y + i * size < imageHeight)
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            if (first.x + j * size < imageWidth)
                            {
                                SmallBucket b = new SmallBucket();
                                b.x         = first.x + j * size;
                                b.y         = first.y + i * size;
                                b.size      = size;
                                b.constrast = 1.0f / size;
                                smallBucketQueue.Enqueue(b);
                            }
                        }
                    }
                }
            }
            return(pixels);
        }
예제 #4
0
        private void computeSubPixel(ImageSample sample, IntersectionState istate)
        {
            float  x  = sample.rx;
            float  y  = sample.ry;
            double q0 = QMC.halton(1, sample.i);
            double q1 = QMC.halton(2, sample.i);
            double q2 = QMC.halton(3, sample.i);

            if (superSampling > 1)
            {
                // multiple sampling
                sample.add(scene.getRadiance(istate, x, y, q1, q2, q0, sample.i));
                for (int i = 1; i < superSampling; i++)
                {
                    double time  = QMC.mod1(q0 + i * invSuperSampling);
                    double lensU = QMC.mod1(q1 + QMC.halton(0, i));
                    double lensV = QMC.mod1(q2 + QMC.halton(1, i));
                    sample.add(scene.getRadiance(istate, x, y, lensU, lensV, time, sample.i + i));
                }
                sample.scale((float)invSuperSampling);
            }
            else
            {
                // single sample
                sample.set(scene.getRadiance(istate, x, y, q1, q2, q0, sample.i));
            }
        }
예제 #5
0
        private void renderBucket(IDisplay display, int bx, int by, int threadID, IntersectionState istate, ShadingCache cache)
        {
            // pixel sized extents
            int x0 = bx * bucketSize;
            int y0 = by * bucketSize;
            int bw = Math.Min(bucketSize, imageWidth - x0);
            int bh = Math.Min(bucketSize, imageHeight - y0);

            // prepare bucket
            display.imagePrepare(x0, y0, bw, bh, threadID);

            Color[] bucketRGB   = new Color[bw * bh];
            float[] bucketAlpha = new float[bw * bh];

            for (int y = 0, i = 0, cy = imageHeight - 1 - y0; y < bh; y++, cy--)
            {
                for (int x = 0, cx = x0; x < bw; x++, i++, cx++)
                {
                    // sample pixel
                    Color  c        = Color.black();
                    float  a        = 0;
                    int    instance = ((cx & ((1 << QMC.MAX_SIGMA_ORDER) - 1)) << QMC.MAX_SIGMA_ORDER) + QMC.sigma(cy & ((1 << QMC.MAX_SIGMA_ORDER) - 1), QMC.MAX_SIGMA_ORDER);
                    double jitterX  = QMC.halton(0, instance);
                    double jitterY  = QMC.halton(1, instance);
                    double jitterT  = QMC.halton(2, instance);
                    double jitterU  = QMC.halton(3, instance);
                    double jitterV  = QMC.halton(4, instance);
                    for (int s = 0; s < numSamples; s++)
                    {
                        float        rx    = cx + 0.5f + (float)warpCubic(QMC.mod1(jitterX + s * invNumSamples));
                        float        ry    = cy + 0.5f + (float)warpCubic(QMC.mod1(jitterY + QMC.halton(0, s)));
                        double       time  = QMC.mod1(jitterT + QMC.halton(1, s));
                        double       lensU = QMC.mod1(jitterU + QMC.halton(2, s));
                        double       lensV = QMC.mod1(jitterV + QMC.halton(3, s));
                        ShadingState state = scene.getRadiance(istate, rx, ry, lensU, lensV, time, instance + s, 5, cache);
                        if (state != null)
                        {
                            c.add(state.getResult());
                            a++;
                        }
                    }
                    bucketRGB[i]   = c.mul(invNumSamples);
                    bucketAlpha[i] = a * invNumSamples;
                    if (cache != null)
                    {
                        cache.reset();
                    }
                }
            }
            // update pixels
            display.imageUpdate(x0, y0, bw, bh, bucketRGB, bucketAlpha);
        }
예제 #6
0
        /**
         * Get a QMC sample from a finite sequence of n elements. This provides
         * better stratification than the infinite version, but does not allow for
         * adaptive sampling.
         *
         * @param j sample number (starts from 0)
         * @param dim dimension to sample
         * @param n number of samples
         * @return pseudo-random value in [0,1)
         */
        public double getRandom(int j, int dim, int n)
        {
            switch (dim)
            {
            case 0:
                return(QMC.mod1(qmcD0I + (double)j / (double)n));

            case 1:
                return(QMC.mod1(qmcD1I + QMC.halton(0, j)));

            default:
                return(QMC.mod1(QMC.halton(d + dim, i) + QMC.halton(dim - 1, j)));
            }
        }
예제 #7
0
            public void Run()
            {
                ByteUtil.InitByteUtil();
                IntersectionState istate = new IntersectionState();

                for (int i = start; i < end; i++)
                {
                    lock (lockObj)
                    {
                        UI.taskUpdate(server.photonCounter);
                        server.photonCounter++;
                        if (UI.taskCanceled())
                        {
                            return;
                        }
                    }

                    int qmcI = i + seed;

                    double rand = QMC.halton(0, qmcI) * histogram[histogram.Length - 1];
                    int    j    = 0;
                    while (rand >= histogram[j] && j < histogram.Length)
                    {
                        j++;
                    }
                    // make sure we didn't pick a zero-probability light
                    if (j == histogram.Length)
                    {
                        continue;
                    }

                    double  randX1 = (j == 0) ? rand / histogram[0] : (rand - histogram[j]) / (histogram[j] - histogram[j - 1]);
                    double  randY1 = QMC.halton(1, qmcI);
                    double  randX2 = QMC.halton(2, qmcI);
                    double  randY2 = QMC.halton(3, qmcI);
                    Point3  pt     = new Point3();
                    Vector3 dir    = new Vector3();
                    Color   power  = new Color();
                    server.lights[j].getPhoton(randX1, randY1, randX2, randY2, pt, dir, power);
                    power.mul(scale);
                    Ray r = new Ray(pt, dir);
                    server.scene.trace(r, istate);
                    if (istate.hit())
                    {
                        server.shadePhoton(ShadingState.createPhotonState(r, istate, qmcI, map, server), power);
                    }
                }
            }
예제 #8
0
        private ShadingState(ShadingState previous, IntersectionState istate, Ray r, int i, int d)
        {
            this.r      = r;
            this.istate = istate;
            this.i      = i;
            this.d      = d;
            time        = istate.time;
            instance    = istate.instance; // local copy
            primitiveID = istate.id;
            hitU        = istate.u;
            hitV        = istate.v;
            hitW        = istate.w;
            // get matrices for current time
            o2w = instance.getObjectToWorld(time);
            w2o = instance.getWorldToObject(time);

            if (previous == null)
            {
                diffuseDepth    = 0;
                reflectionDepth = 0;
                refractionDepth = 0;
            }
            else
            {
                diffuseDepth    = previous.diffuseDepth;
                reflectionDepth = previous.reflectionDepth;
                refractionDepth = previous.refractionDepth;
                server          = previous.server;
                map             = previous.map;
                rx      = previous.rx;
                ry      = previous.ry;
                this.i += previous.i;
                this.d += previous.d;
            }
            behind        = false;
            cosND         = float.NaN;
            includeLights = includeSpecular = true;
            qmcD0I        = QMC.halton(this.d, this.i);
            qmcD1I        = QMC.halton(this.d + 1, this.i);
            result        = null;
            bias          = 0.001f;
        }
예제 #9
0
        public bool update(ParameterList pl, SunflowAPI api)
        {
            updateBasis(pl.getVector("center", null), pl.getVector("up", null));
            numSamples = pl.getInt("samples", numSamples);

            string filename = pl.getstring("texture", null);

            if (filename != null)
            {
                texture = TextureCache.getTexture(api.resolveTextureFilename(filename), true);
            }

            // no texture provided
            if (texture == null)
            {
                return(false);
            }
            Bitmap b = texture.getBitmap();

            if (b == null)
            {
                return(false);
            }

            // rebuild histograms if this is a new texture
            if (filename != null)
            {
                imageHistogram = new float[b.Width][];
                for (int i = 0; i < imageHistogram.Length; i++)
                {
                    imageHistogram[i] = new float[b.Height];
                }
                colHistogram = new float[b.Width];
                float du = 1.0f / b.Width;
                float dv = 1.0f / b.Height;
                for (int x = 0; x < b.Width; x++)
                {
                    for (int y = 0; y < b.Height; y++)
                    {
                        float u = (x + 0.5f) * du;
                        float v = (y + 0.5f) * dv;
                        Color c = texture.getPixel(u, v);
                        // box filter the image
                        // c.add(texture.getPixel(u + du, v));
                        // c.add(texture.getPixel(u + du, v+ dv));
                        // c.add(texture.getPixel(u, v + dv));
                        // c.mul(0.25f);
                        imageHistogram[x][y] = c.getLuminance() * (float)Math.Sin(Math.PI * v);
                        if (y > 0)
                        {
                            imageHistogram[x][y] += imageHistogram[x][y - 1];
                        }
                    }
                    colHistogram[x] = imageHistogram[x][b.Height - 1];
                    if (x > 0)
                    {
                        colHistogram[x] += colHistogram[x - 1];
                    }
                    for (int y = 0; y < b.Height; y++)
                    {
                        imageHistogram[x][y] /= imageHistogram[x][b.Height - 1];
                    }
                }
                for (int x = 0; x < b.Width; x++)
                {
                    colHistogram[x] /= colHistogram[b.Width - 1];
                }
                jacobian = (float)(2 * Math.PI * Math.PI) / (b.Width * b.Height);
            }
            // take fixed samples
            if (pl.getbool("fixed", samples != null))
            {
                // Bitmap loc = new Bitmap(filename);
                samples = new Vector3[numSamples];
                colors  = new Color[numSamples];
                for (int i = 0; i < numSamples; i++)
                {
                    double randX = (double)i / (double)numSamples;
                    double randY = QMC.halton(0, i);
                    int    x     = 0;
                    while (randX >= colHistogram[x] && x < colHistogram.Length - 1)
                    {
                        x++;
                    }
                    float[] rowHistogram = imageHistogram[x];
                    int     y            = 0;
                    while (randY >= rowHistogram[y] && y < rowHistogram.Length - 1)
                    {
                        y++;
                    }
                    // sample from (x, y)
                    float u = (float)((x == 0) ? (randX / colHistogram[0]) : ((randX - colHistogram[x - 1]) / (colHistogram[x] - colHistogram[x - 1])));
                    float v = (float)((y == 0) ? (randY / rowHistogram[0]) : ((randY - rowHistogram[y - 1]) / (rowHistogram[y] - rowHistogram[y - 1])));

                    float px = ((x == 0) ? colHistogram[0] : (colHistogram[x] - colHistogram[x - 1]));
                    float py = ((y == 0) ? rowHistogram[0] : (rowHistogram[y] - rowHistogram[y - 1]));

                    float su = (x + u) / colHistogram.Length;
                    float sv = (y + v) / rowHistogram.Length;

                    float invP = (float)Math.Sin(sv * Math.PI) * jacobian / (numSamples * px * py);
                    samples[i] = getDirection(su, sv);
                    basis.transform(samples[i]);
                    colors[i] = texture.getPixel(su, sv).mul(invP);
                    // loc.setPixel(x, y, Color.YELLOW.copy().mul(1e6f));
                }
                // loc.save("samples.hdr");
            }
            else
            {
                // turn off
                samples = null;
                colors  = null;
            }
            return(true);
        }
예제 #10
0
        private void renderBucket(IDisplay display, int bx, int by, int threadID, IntersectionState istate)
        {
            // pixel sized extents
            int x0 = bx * bucketSize;
            int y0 = by * bucketSize;
            int bw = Math.Min(bucketSize, imageWidth - x0);
            int bh = Math.Min(bucketSize, imageHeight - y0);

            // prepare bucket
            display.imagePrepare(x0, y0, bw, bh, threadID);

            Color[] bucketRGB   = new Color[bw * bh];
            float[] bucketAlpha = new float[bw * bh];

            // subpixel extents
            int sx0 = x0 * subPixelSize - fs;
            int sy0 = y0 * subPixelSize - fs;
            int sbw = bw * subPixelSize + fs * 2;
            int sbh = bh * subPixelSize + fs * 2;

            // round up to align with maximum step size
            sbw = (sbw + (maxStepSize - 1)) & (~(maxStepSize - 1));
            sbh = (sbh + (maxStepSize - 1)) & (~(maxStepSize - 1));
            // extra padding as needed
            if (maxStepSize > 1)
            {
                sbw++;
                sbh++;
            }
            // allocate bucket memory
            ImageSample[] samples = new ImageSample[sbw * sbh];
            // allocate samples and compute jitter offsets
            float invSubPixelSize = 1.0f / subPixelSize;

            for (int y = 0, index = 0; y < sbh; y++)
            {
                for (int x = 0; x < sbw; x++, index++)
                {
                    int   sx = sx0 + x;
                    int   sy = sy0 + y;
                    int   j  = sx & (sigmaLength - 1);
                    int   k  = sy & (sigmaLength - 1);
                    int   i  = (j << sigmaOrder) + QMC.sigma(k, sigmaOrder);
                    float dx = useJitter ? (float)QMC.halton(0, k) : 0.5f;
                    float dy = useJitter ? (float)QMC.halton(0, j) : 0.5f;
                    float rx = (sx + dx) * invSubPixelSize;
                    float ry = (sy + dy) * invSubPixelSize;
                    ry             = imageHeight - ry;
                    samples[index] = new ImageSample(rx, ry, i);
                }
            }
            for (int x = 0; x < sbw - 1; x += maxStepSize)
            {
                for (int y = 0; y < sbh - 1; y += maxStepSize)
                {
                    refineSamples(samples, sbw, x, y, maxStepSize, thresh, istate);
                }
            }
            if (dumpBuckets)
            {
                UI.printInfo(UI.Module.BCKT, "Dumping bucket [{0}, {1}] to file ...", bx, by);
                GenericBitmap bitmap = new GenericBitmap(sbw, sbh);
                for (int y = sbh - 1, index = 0; y >= 0; y--)
                {
                    for (int x = 0; x < sbw; x++, index++)
                    {
                        bitmap.writePixel(x, y, samples[index].c, samples[index].alpha);
                    }
                }
                bitmap.save(string.Format("bucket_{0}_{1}.png", bx, by));
            }
            if (displayAA)
            {
                // color coded image of what is visible
                float invArea = invSubPixelSize * invSubPixelSize;
                for (int y = 0, index = 0; y < bh; y++)
                {
                    for (int x = 0; x < bw; x++, index++)
                    {
                        int sampled = 0;
                        for (int i = 0; i < subPixelSize; i++)
                        {
                            for (int j = 0; j < subPixelSize; j++)
                            {
                                int sx = x * subPixelSize + fs + i;
                                int sy = y * subPixelSize + fs + j;
                                int s  = sx + sy * sbw;
                                sampled += samples[s].sampled() ? 1 : 0;
                            }
                        }
                        bucketRGB[index]   = new Color(sampled * invArea);
                        bucketAlpha[index] = 1.0f;
                    }
                }
            }
            else
            {
                // filter samples into pixels
                float cy = imageHeight - (y0 + 0.5f);
                for (int y = 0, index = 0; y < bh; y++, cy--)
                {
                    float cx = x0 + 0.5f;
                    for (int x = 0; x < bw; x++, index++, cx++)
                    {
                        Color c      = Color.black();
                        float a      = 0.0f;
                        float weight = 0.0f;
                        for (int j = -fs, sy = y * subPixelSize; j <= fs; j++, sy++)
                        {
                            for (int i = -fs, sx = x * subPixelSize, s = sx + sy * sbw; i <= fs; i++, sx++, s++)
                            {
                                float dx = samples[s].rx - cx;
                                if (Math.Abs(dx) > fhs)
                                {
                                    continue;
                                }
                                float dy = samples[s].ry - cy;
                                if (Math.Abs(dy) > fhs)
                                {
                                    continue;
                                }
                                float f = filter.get(dx, dy);
                                c.madd(f, samples[s].c);
                                a      += f * samples[s].alpha;
                                weight += f;
                            }
                        }
                        float invWeight = 1.0f / weight;
                        c.mul(invWeight);
                        a *= invWeight;
                        bucketRGB[index]   = c;
                        bucketAlpha[index] = a;
                    }
                }
            }
            // update pixels
            display.imageUpdate(x0, y0, bw, bh, bucketRGB, bucketAlpha);
        }