⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bucketrenderer.java

📁 Sunflow是一个照片级的渲染系统
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package org.sunflow.core.renderer;

import org.sunflow.core.BucketOrder;
import org.sunflow.core.Display;
import org.sunflow.core.Filter;
import org.sunflow.core.ImageSampler;
import org.sunflow.core.Instance;
import org.sunflow.core.IntersectionState;
import org.sunflow.core.Options;
import org.sunflow.core.Scene;
import org.sunflow.core.Shader;
import org.sunflow.core.ShadingState;
import org.sunflow.core.bucket.BucketOrderFactory;
import org.sunflow.core.filter.BoxFilter;
import org.sunflow.core.filter.FilterFactory;
import org.sunflow.image.Bitmap;
import org.sunflow.image.Color;
import org.sunflow.math.MathUtils;
import org.sunflow.math.QMC;
import org.sunflow.system.Timer;
import org.sunflow.system.UI;
import org.sunflow.system.UI.Module;

public class BucketRenderer implements ImageSampler {
    private Scene scene;
    private Display display;
    // resolution
    private int imageWidth;
    private int imageHeight;
    // bucketing
    private String bucketOrderName;
    private BucketOrder bucketOrder;
    private int bucketSize;
    private int bucketCounter;
    private int[] bucketCoords;
    private boolean dumpBuckets;

    // anti-aliasing
    private int minAADepth;
    private int maxAADepth;
    private int superSampling;
    private float contrastThreshold;
    private boolean jitter;
    private boolean displayAA;

    // derived quantities
    private double invSuperSampling;
    private int subPixelSize;
    private int minStepSize;
    private int maxStepSize;
    private int[] sigma;
    private float thresh;
    private boolean useJitter;

    // filtering
    private String filterName;
    private Filter filter;
    private int fs;
    private float fhs;

    public BucketRenderer() {
        bucketSize = 32;
        bucketOrderName = "hilbert";
        displayAA = false;
        contrastThreshold = 0.1f;
        filterName = "box";
        jitter = false; // off by default
        dumpBuckets = false; // for debugging only - not user settable
    }

    public boolean 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.getBoolean("aa.display", displayAA);
        jitter = options.getBoolean("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 = FilterFactory.get(filterName);
        // adjust filter
        if (filter == null) {
            UI.printWarning(Module.BCKT, "Unrecognized filter type: \"%s\" - defaulting to box", filterName);
            filter = new BoxFilter(1);
            filterName = "box";
        }
        fhs = filter.getSize() * 0.5f;
        fs = (int) Math.ceil(subPixelSize * (fhs - 0.5f));

        // prepare QMC sampling
        sigma = QMC.generateSigmaTable(subPixelSize << 7);
        UI.printInfo(Module.BCKT, "Bucket renderer settings:");
        UI.printInfo(Module.BCKT, "  * Resolution:         %dx%d", imageWidth, imageHeight);
        UI.printInfo(Module.BCKT, "  * Bucket size:        %d", bucketSize);
        UI.printInfo(Module.BCKT, "  * Number of buckets:  %dx%d", numBucketsX, numBucketsY);
        if (minAADepth != maxAADepth)
            UI.printInfo(Module.BCKT, "  * Anti-aliasing:      %s -> %s (adaptive)", aaDepthToString(minAADepth), aaDepthToString(maxAADepth));
        else
            UI.printInfo(Module.BCKT, "  * Anti-aliasing:      %s (fixed)", aaDepthToString(minAADepth));
        UI.printInfo(Module.BCKT, "  * Rays per sample:    %d", superSampling);
        UI.printInfo(Module.BCKT, "  * Subpixel jitter:    %s", useJitter ? "on" : (jitter ? "auto-off" : "off"));
        UI.printInfo(Module.BCKT, "  * Contrast threshold: %.2f", contrastThreshold);
        UI.printInfo(Module.BCKT, "  * Filter type:        %s", filterName);
        UI.printInfo(Module.BCKT, "  * Filter size:        %.2f pixels", filter.getSize());
        return true;
    }

    private String aaDepthToString(int depth) {
        int pixelAA = (depth) < 0 ? -(1 << (-depth)) : (1 << depth);
        return String.format("%s%d sample%s", depth < 0 ? "1/" : "", pixelAA * pixelAA, depth == 0 ? "" : "s");
    }

    public void render(Display display) {
        this.display = display;
        display.imageBegin(imageWidth, imageHeight, bucketSize);
        // set members variables
        bucketCounter = 0;
        // start task
        UI.taskStart("Rendering", 0, bucketCoords.length);
        Timer timer = new Timer();
        timer.start();
        Thread[] renderThreads = new Thread[scene.getThreads()];
        for (int i = 0; i < renderThreads.length; i++) {
            renderThreads[i] = new BucketThread(i);
            renderThreads[i].setPriority(scene.getThreadPriority());
            renderThreads[i].start();
        }
        for (int i = 0; i < renderThreads.length; i++) {
            try {
                renderThreads[i].join();
            } catch (InterruptedException e) {
                UI.printError(Module.BCKT, "Bucket processing thread %d of %d was interrupted", i + 1, renderThreads.length);
            }
        }
        UI.taskStop();
        timer.end();
        UI.printInfo(Module.BCKT, "Render time: %s", timer.toString());
        display.imageEnd();
    }

    private class BucketThread extends Thread {
        private int threadID;

        BucketThread(int threadID) {
            this.threadID = threadID;
        }

        public void run() {
            IntersectionState istate = new IntersectionState();
            while (true) {
                int bx, by;
                synchronized (BucketRenderer.this) {
                    if (bucketCounter >= bucketCoords.length)
                        return;
                    UI.taskUpdate(bucketCounter);
                    bx = bucketCoords[bucketCounter + 0];
                    by = bucketCoords[bucketCounter + 1];
                    bucketCounter += 2;
                }
                renderBucket(display, bx, by, threadID, istate);
                if (UI.taskCanceled())
                    return;
            }
        }
    }

    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];

        // 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++) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -