Search in sources :

Example 11 with Color

use of org.sunflow.image.Color in project joons-renderer by joonhyublee.

the class LightServer method calculatePhotons.

boolean calculatePhotons(final PhotonStore map, String type, final int seed, Options options) {
    if (map == null) {
        return true;
    }
    if (lights.length == 0) {
        UI.printError(Module.LIGHT, "Unable to trace %s photons, no lights in scene", type);
        return false;
    }
    final float[] histogram = new float[lights.length];
    histogram[0] = lights[0].getPower();
    for (int i = 1; i < lights.length; i++) {
        histogram[i] = histogram[i - 1] + lights[i].getPower();
    }
    UI.printInfo(Module.LIGHT, "Tracing %s photons ...", type);
    map.prepare(options, scene.getBounds());
    int numEmittedPhotons = map.numEmit();
    if (numEmittedPhotons <= 0 || histogram[histogram.length - 1] <= 0) {
        UI.printError(Module.LIGHT, "Photon mapping enabled, but no %s photons to emit", type);
        return false;
    }
    UI.taskStart("Tracing " + type + " photons", 0, numEmittedPhotons);
    Thread[] photonThreads = new Thread[scene.getThreads()];
    final float scale = 1.0f / numEmittedPhotons;
    int delta = numEmittedPhotons / photonThreads.length;
    photonCounter = 0;
    Timer photonTimer = new Timer();
    photonTimer.start();
    for (int i = 0; i < photonThreads.length; i++) {
        final int threadID = i;
        final int start = threadID * delta;
        final int end = (threadID == (photonThreads.length - 1)) ? numEmittedPhotons : (threadID + 1) * delta;
        photonThreads[i] = new Thread(new Runnable() {

            public void run() {
                IntersectionState istate = new IntersectionState();
                for (int i = start; i < end; i++) {
                    synchronized (LightServer.this) {
                        UI.taskUpdate(photonCounter);
                        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();
                    lights[j].getPhoton(randX1, randY1, randX2, randY2, pt, dir, power);
                    power.mul(scale);
                    Ray r = new Ray(pt, dir);
                    scene.trace(r, istate);
                    if (istate.hit()) {
                        shadePhoton(ShadingState.createPhotonState(r, istate, qmcI, map, LightServer.this), power);
                    }
                }
            }
        });
        photonThreads[i].setPriority(scene.getThreadPriority());
        photonThreads[i].start();
    }
    for (int i = 0; i < photonThreads.length; i++) {
        try {
            photonThreads[i].join();
        } catch (InterruptedException e) {
            UI.printError(Module.LIGHT, "Photon thread %d of %d was interrupted", i + 1, photonThreads.length);
            return false;
        }
    }
    if (UI.taskCanceled()) {
        // shut down task cleanly
        UI.taskStop();
        return false;
    }
    photonTimer.end();
    UI.taskStop();
    UI.printInfo(Module.LIGHT, "Tracing time for %s photons: %s", type, photonTimer.toString());
    map.init();
    return true;
}
Also used : Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) Point3(org.sunflow.math.Point3) Timer(org.sunflow.system.Timer)

Example 12 with Color

use of org.sunflow.image.Color in project joons-renderer by joonhyublee.

the class BucketRenderer method renderBucket.

private void renderBucket(Display 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(Module.BCKT, "Dumping bucket [%d, %d] 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_%04d_%04d.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;
                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);
}
Also used : GenericBitmap(org.sunflow.image.formats.GenericBitmap) Color(org.sunflow.image.Color)

Example 13 with Color

use of org.sunflow.image.Color in project joons-renderer by joonhyublee.

the class ProgressiveRenderer method progressiveRenderNext.

private int progressiveRenderNext(IntersectionState istate) {
    final int TASK_SIZE = 16;
    SmallBucket first = smallBucketQueue.poll();
    if (first == null) {
        return 0;
    }
    int ds = first.size / TASK_SIZE;
    boolean useMask = !smallBucketQueue.isEmpty();
    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 & ((1 << QMC.MAX_SIGMA_ORDER) - 1)) << QMC.MAX_SIGMA_ORDER) + QMC.sigma(y & ((1 << QMC.MAX_SIGMA_ORDER) - 1), QMC.MAX_SIGMA_ORDER);
            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, 4, null);
            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, state == null ? 0 : 1);
        }
    }
    if (first.size >= 2 * TASK_SIZE) {
        // generate child buckets
        int size = 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.put(b);
                    }
                }
            }
        }
    }
    return pixels;
}
Also used : ShadingState(org.sunflow.core.ShadingState) Color(org.sunflow.image.Color)

Example 14 with Color

use of org.sunflow.image.Color in project joons-renderer by joonhyublee.

the class AnisotropicWardShader method getRadiance.

public Color getRadiance(ShadingState state) {
    // make sure we are on the right side of the material
    state.faceforward();
    OrthoNormalBasis onb = state.getBasis();
    // direct lighting and caustics
    state.initLightSamples();
    state.initCausticSamples();
    Color lr = Color.black();
    // compute specular contribution
    if (state.includeSpecular()) {
        Vector3 in = state.getRay().getDirection().negate(new Vector3());
        for (LightSample sample : state) {
            float cosNL = sample.dot(state.getNormal());
            float fr = brdf(in, sample.getShadowRay().getDirection(), onb);
            lr.madd(cosNL * fr, sample.getSpecularRadiance());
        }
        // indirect lighting - specular
        if (numRays > 0) {
            int n = state.getDepth() == 0 ? numRays : 1;
            for (int i = 0; i < n; i++) {
                // specular indirect lighting
                double r1 = state.getRandom(i, 0, n);
                double r2 = state.getRandom(i, 1, n);
                float alphaRatio = alphaY / alphaX;
                float phi = 0;
                if (r1 < 0.25) {
                    double val = 4 * r1;
                    phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
                } else if (r1 < 0.5) {
                    double val = 1 - 4 * (0.5 - r1);
                    phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
                    phi = (float) Math.PI - phi;
                } else if (r1 < 0.75) {
                    double val = 4 * (r1 - 0.5);
                    phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
                    phi += Math.PI;
                } else {
                    double val = 1 - 4 * (1 - r1);
                    phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
                    phi = 2 * (float) Math.PI - phi;
                }
                float cosPhi = (float) Math.cos(phi);
                float sinPhi = (float) Math.sin(phi);
                float denom = (cosPhi * cosPhi) / (alphaX * alphaX) + (sinPhi * sinPhi) / (alphaY * alphaY);
                float theta = (float) Math.atan(Math.sqrt(-Math.log(1 - r2) / denom));
                float sinTheta = (float) Math.sin(theta);
                float cosTheta = (float) Math.cos(theta);
                Vector3 h = new Vector3();
                h.x = sinTheta * cosPhi;
                h.y = sinTheta * sinPhi;
                h.z = cosTheta;
                onb.transform(h);
                Vector3 o = new Vector3();
                float ih = Vector3.dot(h, in);
                o.x = 2 * ih * h.x - in.x;
                o.y = 2 * ih * h.y - in.y;
                o.z = 2 * ih * h.z - in.z;
                float no = onb.untransformZ(o);
                float ni = onb.untransformZ(in);
                float w = ih * cosTheta * cosTheta * cosTheta * (float) Math.sqrt(Math.abs(no / ni));
                Ray r = new Ray(state.getPoint(), o);
                lr.madd(w / n, state.traceGlossy(r, i));
            }
        }
        lr.mul(rhoS);
    }
    // add diffuse contribution
    lr.add(state.diffuse(getDiffuse(state)));
    return lr;
}
Also used : LightSample(org.sunflow.core.LightSample) Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) Ray(org.sunflow.core.Ray) OrthoNormalBasis(org.sunflow.math.OrthoNormalBasis)

Example 15 with Color

use of org.sunflow.image.Color in project joons-renderer by joonhyublee.

the class NormalShader method getRadiance.

public Color getRadiance(ShadingState state) {
    Vector3 n = state.getNormal();
    if (n == null) {
        return Color.BLACK;
    }
    float r = (n.x + 1) * 0.5f;
    float g = (n.y + 1) * 0.5f;
    float b = (n.z + 1) * 0.5f;
    return new Color(r, g, b);
}
Also used : Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3)

Aggregations

Color (org.sunflow.image.Color)48 Vector3 (org.sunflow.math.Vector3)34 Ray (org.sunflow.core.Ray)22 OrthoNormalBasis (org.sunflow.math.OrthoNormalBasis)15 LightSample (org.sunflow.core.LightSample)8 Point3 (org.sunflow.math.Point3)7 ShadingState (org.sunflow.core.ShadingState)6 Bitmap (org.sunflow.image.Bitmap)2 XYZColor (org.sunflow.image.XYZColor)2 Timer (org.sunflow.system.Timer)2 FileWriter (java.io.FileWriter)1 IOException (java.io.IOException)1 ConstantSpectralCurve (org.sunflow.image.ConstantSpectralCurve)1 GenericBitmap (org.sunflow.image.formats.GenericBitmap)1 BoundingBox (org.sunflow.math.BoundingBox)1 IntArray (org.sunflow.util.IntArray)1