Search in sources :

Example 36 with Color

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

the class InstantGI method getIrradiance.

@Override
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
    float b = (float) Math.PI * c / diffuseReflectance.getMax();
    Color irr = Color.black();
    Point3 p = state.getPoint();
    Vector3 n = state.getNormal();
    int set = (int) (state.getRandom(0, 1, 1) * numSets);
    for (PointLight vpl : virtualLights[set]) {
        Ray r = new Ray(p, vpl.p);
        float dotNlD = -(r.dx * vpl.n.x + r.dy * vpl.n.y + r.dz * vpl.n.z);
        float dotND = r.dx * n.x + r.dy * n.y + r.dz * n.z;
        if (dotNlD > 0 && dotND > 0) {
            float r2 = r.getMax() * r.getMax();
            Color opacity = state.traceShadow(r);
            Color power = Color.blend(vpl.power, Color.BLACK, opacity);
            float g = (dotND * dotNlD) / r2;
            irr.madd(0.25f * Math.min(g, b), power);
        }
    }
    // bias compensation
    int nb = (state.getDiffuseDepth() == 0 || numBias <= 0) ? numBias : 1;
    if (nb <= 0) {
        return irr;
    }
    OrthoNormalBasis onb = state.getBasis();
    Vector3 w = new Vector3();
    float scale = (float) Math.PI / nb;
    for (int i = 0; i < nb; i++) {
        float xi = (float) state.getRandom(i, 0, nb);
        float xj = (float) state.getRandom(i, 1, nb);
        float phi = (float) (xi * 2 * Math.PI);
        float cosPhi = (float) Math.cos(phi);
        float sinPhi = (float) Math.sin(phi);
        float sinTheta = (float) Math.sqrt(xj);
        float cosTheta = (float) Math.sqrt(1.0f - xj);
        w.x = cosPhi * sinTheta;
        w.y = sinPhi * sinTheta;
        w.z = cosTheta;
        onb.transform(w);
        Ray r = new Ray(state.getPoint(), w);
        r.setMax((float) Math.sqrt(cosTheta / b));
        ShadingState temp = state.traceFinalGather(r, i);
        if (temp != null) {
            temp.getInstance().prepareShadingState(temp);
            if (temp.getShader() != null) {
                float dist = temp.getRay().getMax();
                float r2 = dist * dist;
                float cosThetaY = -Vector3.dot(w, temp.getNormal());
                if (cosThetaY > 0) {
                    float g = (cosTheta * cosThetaY) / r2;
                    // was this path accounted for yet?
                    if (g > b) {
                        irr.madd(scale * (g - b) / g, temp.getShader().getRadiance(temp));
                    }
                }
            }
        }
    }
    return irr;
}
Also used : Point3(org.sunflow.math.Point3) ShadingState(org.sunflow.core.ShadingState) Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) Ray(org.sunflow.core.Ray) OrthoNormalBasis(org.sunflow.math.OrthoNormalBasis)

Example 37 with Color

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

the class PathTracingGIEngine method getIrradiance.

@Override
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
    if (samples <= 0) {
        return Color.BLACK;
    }
    // compute new sample
    Color irr = Color.black();
    OrthoNormalBasis onb = state.getBasis();
    Vector3 w = new Vector3();
    int n = state.getDiffuseDepth() == 0 ? samples : 1;
    for (int i = 0; i < n; i++) {
        float xi = (float) state.getRandom(i, 0, n);
        float xj = (float) state.getRandom(i, 1, n);
        float phi = (float) (xi * 2 * Math.PI);
        float cosPhi = (float) Math.cos(phi);
        float sinPhi = (float) Math.sin(phi);
        float sinTheta = (float) Math.sqrt(xj);
        float cosTheta = (float) Math.sqrt(1.0f - xj);
        w.x = cosPhi * sinTheta;
        w.y = sinPhi * sinTheta;
        w.z = cosTheta;
        onb.transform(w);
        ShadingState temp = state.traceFinalGather(new Ray(state.getPoint(), w), i);
        if (temp != null) {
            temp.getInstance().prepareShadingState(temp);
            if (temp.getShader() != null) {
                irr.add(temp.getShader().getRadiance(temp));
            }
        }
    }
    irr.mul((float) Math.PI / n);
    return irr;
}
Also used : ShadingState(org.sunflow.core.ShadingState) Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) Ray(org.sunflow.core.Ray) OrthoNormalBasis(org.sunflow.math.OrthoNormalBasis)

Example 38 with Color

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

the class ImageBasedLight method update.

public boolean update(ParameterList pl, SunflowAPI api) {
    updateBasis(pl.getVector("center", null), pl.getVector("up", null));
    numSamples = pl.getInt("samples", numSamples);
    numLowSamples = pl.getInt("lowsamples", numLowSamples);
    String filename = pl.getString("texture", null);
    if (filename != null) {
        texture = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
    }
    // 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.getWidth()][b.getHeight()];
        colHistogram = new float[b.getWidth()];
        float du = 1.0f / b.getWidth();
        float dv = 1.0f / b.getHeight();
        for (int x = 0; x < b.getWidth(); x++) {
            for (int y = 0; y < b.getHeight(); y++) {
                float u = (x + 0.5f) * du;
                float v = (y + 0.5f) * dv;
                Color c = texture.getPixel(u, v);
                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.getHeight() - 1];
            if (x > 0) {
                colHistogram[x] += colHistogram[x - 1];
            }
            for (int y = 0; y < b.getHeight(); y++) {
                imageHistogram[x][y] /= imageHistogram[x][b.getHeight() - 1];
            }
        }
        for (int x = 0; x < b.getWidth(); x++) {
            colHistogram[x] /= colHistogram[b.getWidth() - 1];
        }
        jacobian = (float) (2 * Math.PI * Math.PI) / (b.getWidth() * b.getHeight());
    }
    // take fixed samples
    if (pl.getBoolean("fixed", samples != null)) {
        // high density samples
        samples = new Vector3[numSamples];
        colors = new Color[numSamples];
        generateFixedSamples(samples, colors);
        // low density samples
        lowSamples = new Vector3[numLowSamples];
        lowColors = new Color[numLowSamples];
        generateFixedSamples(lowSamples, lowColors);
    } else {
        // turn off
        samples = lowSamples = null;
        colors = lowColors = null;
    }
    return true;
}
Also used : Bitmap(org.sunflow.image.Bitmap) Color(org.sunflow.image.Color)

Example 39 with Color

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

the class SphereLight method getSamples.

public void getSamples(ShadingState state) {
    if (getNumSamples() <= 0) {
        return;
    }
    Vector3 wc = Point3.sub(center, state.getPoint(), new Vector3());
    float l2 = wc.lengthSquared();
    if (l2 <= r2) {
        // inside the sphere?
        return;
    }
    // top of the sphere as viewed from the current shading point
    float topX = wc.x + state.getNormal().x * radius;
    float topY = wc.y + state.getNormal().y * radius;
    float topZ = wc.z + state.getNormal().z * radius;
    if (state.getNormal().dot(topX, topY, topZ) <= 0) {
        // top of the sphere is below the horizon
        return;
    }
    float cosThetaMax = (float) Math.sqrt(Math.max(0, 1 - r2 / Vector3.dot(wc, wc)));
    OrthoNormalBasis basis = OrthoNormalBasis.makeFromW(wc);
    int samples = state.getDiffuseDepth() > 0 ? 1 : getNumSamples();
    float scale = (float) (2 * Math.PI * (1 - cosThetaMax));
    Color c = Color.mul(scale / samples, radiance);
    for (int i = 0; i < samples; i++) {
        // random offset on unit square
        double randX = state.getRandom(i, 0, samples);
        double randY = state.getRandom(i, 1, samples);
        // cone sampling
        double cosTheta = (1 - randX) * cosThetaMax + randX;
        double sinTheta = Math.sqrt(1 - cosTheta * cosTheta);
        double phi = randY * 2 * Math.PI;
        Vector3 dir = new Vector3((float) (Math.cos(phi) * sinTheta), (float) (Math.sin(phi) * sinTheta), (float) cosTheta);
        basis.transform(dir);
        // check that the direction of the sample is the same as the
        // normal
        float cosNx = Vector3.dot(dir, state.getNormal());
        if (cosNx <= 0) {
            continue;
        }
        float ocx = state.getPoint().x - center.x;
        float ocy = state.getPoint().y - center.y;
        float ocz = state.getPoint().z - center.z;
        float qa = Vector3.dot(dir, dir);
        float qb = 2 * ((dir.x * ocx) + (dir.y * ocy) + (dir.z * ocz));
        float qc = ((ocx * ocx) + (ocy * ocy) + (ocz * ocz)) - r2;
        double[] t = Solvers.solveQuadric(qa, qb, qc);
        if (t == null) {
            continue;
        }
        LightSample dest = new LightSample();
        // compute shadow ray to the sampled point
        dest.setShadowRay(new Ray(state.getPoint(), dir));
        // FIXME: arbitrary bias, should handle as in other places
        dest.getShadowRay().setMax((float) t[0] - 1e-3f);
        // prepare sample
        dest.setRadiance(c, c);
        dest.traceShadow(state);
        state.addSample(dest);
    }
}
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 40 with Color

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

the class TriangleMeshLight method getSamples.

public void getSamples(ShadingState state) {
    if (numSamples == 0) {
        return;
    }
    Vector3 n = state.getNormal();
    Point3 p = state.getPoint();
    for (int tri3 = 0, i = 0; tri3 < triangles.length; tri3 += 3, i++) {
        // vector towards each vertex of the light source
        Vector3 p0 = Point3.sub(getPoint(triangles[tri3 + 0]), p, new Vector3());
        // cull triangle if it is facing the wrong way
        if (Vector3.dot(p0, ngs[i]) >= 0) {
            continue;
        }
        Vector3 p1 = Point3.sub(getPoint(triangles[tri3 + 1]), p, new Vector3());
        Vector3 p2 = Point3.sub(getPoint(triangles[tri3 + 2]), p, new Vector3());
        // if all three vertices are below the hemisphere, stop
        if (Vector3.dot(p0, n) <= 0 && Vector3.dot(p1, n) <= 0 && Vector3.dot(p2, n) <= 0) {
            continue;
        }
        p0.normalize();
        p1.normalize();
        p2.normalize();
        float dot = Vector3.dot(p2, p0);
        Vector3 h = new Vector3();
        h.x = p2.x - dot * p0.x;
        h.y = p2.y - dot * p0.y;
        h.z = p2.z - dot * p0.z;
        float hlen = h.length();
        if (hlen > 1e-6f) {
            h.div(hlen);
        } else {
            continue;
        }
        Vector3 n0 = Vector3.cross(p0, p1, new Vector3());
        float len0 = n0.length();
        if (len0 > 1e-6f) {
            n0.div(len0);
        } else {
            continue;
        }
        Vector3 n1 = Vector3.cross(p1, p2, new Vector3());
        float len1 = n1.length();
        if (len1 > 1e-6f) {
            n1.div(len1);
        } else {
            continue;
        }
        Vector3 n2 = Vector3.cross(p2, p0, new Vector3());
        float len2 = n2.length();
        if (len2 > 1e-6f) {
            n2.div(len2);
        } else {
            continue;
        }
        float cosAlpha = MathUtils.clamp(-Vector3.dot(n2, n0), -1.0f, 1.0f);
        float cosBeta = MathUtils.clamp(-Vector3.dot(n0, n1), -1.0f, 1.0f);
        float cosGamma = MathUtils.clamp(-Vector3.dot(n1, n2), -1.0f, 1.0f);
        float alpha = (float) Math.acos(cosAlpha);
        float beta = (float) Math.acos(cosBeta);
        float gamma = (float) Math.acos(cosGamma);
        float area = alpha + beta + gamma - (float) Math.PI;
        float cosC = MathUtils.clamp(Vector3.dot(p0, p1), -1.0f, 1.0f);
        float salpha = (float) Math.sin(alpha);
        float product = salpha * cosC;
        // use lower sampling depth for diffuse bounces
        int samples = state.getDiffuseDepth() > 0 ? 1 : numSamples;
        Color c = Color.mul(area / samples, radiance);
        for (int j = 0; j < samples; j++) {
            // random offset on unit square
            double randX = state.getRandom(j, 0, samples);
            double randY = state.getRandom(j, 1, samples);
            float phi = (float) randX * area - alpha + (float) Math.PI;
            float sinPhi = (float) Math.sin(phi);
            float cosPhi = (float) Math.cos(phi);
            float u = cosPhi + cosAlpha;
            float v = sinPhi - product;
            float q = (-v + cosAlpha * (cosPhi * -v + sinPhi * u)) / (salpha * (sinPhi * -v - cosPhi * u));
            float q1 = 1.0f - q * q;
            if (q1 < 0.0f) {
                q1 = 0.0f;
            }
            float sqrtq1 = (float) Math.sqrt(q1);
            float ncx = q * p0.x + sqrtq1 * h.x;
            float ncy = q * p0.y + sqrtq1 * h.y;
            float ncz = q * p0.z + sqrtq1 * h.z;
            dot = p1.dot(ncx, ncy, ncz);
            float z = 1.0f - (float) randY * (1.0f - dot);
            float z1 = 1.0f - z * z;
            if (z1 < 0.0f) {
                z1 = 0.0f;
            }
            Vector3 nd = new Vector3();
            nd.x = ncx - dot * p1.x;
            nd.y = ncy - dot * p1.y;
            nd.z = ncz - dot * p1.z;
            nd.normalize();
            float sqrtz1 = (float) Math.sqrt(z1);
            Vector3 result = new Vector3();
            result.x = z * p1.x + sqrtz1 * nd.x;
            result.y = z * p1.y + sqrtz1 * nd.y;
            result.z = z * p1.z + sqrtz1 * nd.z;
            // the right direction
            if (Vector3.dot(result, n) > 0 && Vector3.dot(result, state.getGeoNormal()) > 0 && Vector3.dot(result, ngs[i]) < 0) {
                // compute intersection with triangle (if any)
                Ray shadowRay = new Ray(state.getPoint(), result);
                if (!intersectTriangleKensler(tri3, shadowRay)) {
                    continue;
                }
                LightSample dest = new LightSample();
                dest.setShadowRay(shadowRay);
                // prepare sample
                dest.setRadiance(c, c);
                dest.traceShadow(state);
                state.addSample(dest);
            }
        }
    }
}
Also used : Point3(org.sunflow.math.Point3) LightSample(org.sunflow.core.LightSample) Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) Ray(org.sunflow.core.Ray)

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