Search in sources :

Example 21 with Ray

use of org.sunflow.core.Ray in project joons-renderer by joonhyublee.

the class GlassShader method getRadiance.

public Color getRadiance(ShadingState state) {
    if (!state.includeSpecular()) {
        return Color.BLACK;
    }
    Vector3 reflDir = new Vector3();
    Vector3 refrDir = new Vector3();
    state.faceforward();
    float cos = state.getCosND();
    boolean inside = state.isBehind();
    float neta = inside ? eta : 1.0f / eta;
    float dn = 2 * cos;
    reflDir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
    reflDir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
    reflDir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
    // refracted ray
    float arg = 1 - (neta * neta * (1 - (cos * cos)));
    boolean tir = arg < 0;
    if (tir) {
        refrDir.x = refrDir.y = refrDir.z = 0;
    } else {
        float nK = (neta * cos) - (float) Math.sqrt(arg);
        refrDir.x = (neta * state.getRay().dx) + (nK * state.getNormal().x);
        refrDir.y = (neta * state.getRay().dy) + (nK * state.getNormal().y);
        refrDir.z = (neta * state.getRay().dz) + (nK * state.getNormal().z);
    }
    // compute Fresnel terms
    float cosTheta1 = Vector3.dot(state.getNormal(), reflDir);
    float cosTheta2 = -Vector3.dot(state.getNormal(), refrDir);
    float pPara = (cosTheta1 - eta * cosTheta2) / (cosTheta1 + eta * cosTheta2);
    float pPerp = (eta * cosTheta1 - cosTheta2) / (eta * cosTheta1 + cosTheta2);
    float kr = 0.5f * (pPara * pPara + pPerp * pPerp);
    float kt = 1 - kr;
    Color absorbtion = null;
    if (inside && absorptionDistance > 0) {
        // this ray is inside the object and leaving it
        // compute attenuation that occured along the ray
        absorbtion = Color.mul(-state.getRay().getMax() / absorptionDistance, absorptionColor.copy().opposite()).exp();
        if (absorbtion.isBlack()) {
            // nothing goes through
            return Color.BLACK;
        }
    }
    // refracted ray
    Color ret = Color.black();
    if (!tir) {
        ret.madd(kt, state.traceRefraction(new Ray(state.getPoint(), refrDir), 0)).mul(color);
    }
    if (!inside || tir) {
        ret.add(Color.mul(kr, state.traceReflection(new Ray(state.getPoint(), reflDir), 0)).mul(color));
    }
    return absorbtion != null ? ret.mul(absorbtion) : ret;
}
Also used : Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) Ray(org.sunflow.core.Ray)

Example 22 with Ray

use of org.sunflow.core.Ray 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 23 with Ray

use of org.sunflow.core.Ray 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 24 with Ray

use of org.sunflow.core.Ray 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 25 with Ray

use of org.sunflow.core.Ray 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

Ray (org.sunflow.core.Ray)27 Vector3 (org.sunflow.math.Vector3)25 Color (org.sunflow.image.Color)22 OrthoNormalBasis (org.sunflow.math.OrthoNormalBasis)13 LightSample (org.sunflow.core.LightSample)9 Point3 (org.sunflow.math.Point3)5 ShadingState (org.sunflow.core.ShadingState)3 Instance (org.sunflow.core.Instance)1 Shader (org.sunflow.core.Shader)1 XYZColor (org.sunflow.image.XYZColor)1