Search in sources :

Example 66 with Vector3

use of org.sunflow.math.Vector3 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)

Example 67 with Vector3

use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.

the class ShadingState method occlusion.

/**
 * Ambient occlusion routine, returns a value between bright and dark
 * depending on the amount of geometric occlusion in the scene.
 *
 * @param samples number of sample rays
 * @param maxDist maximum length of the rays
 * @param bright color when nothing is occluded
 * @param dark color when fully occluded
 * @return occlusion color
 */
public final Color occlusion(int samples, float maxDist, Color bright, Color dark) {
    if (n == null) {
        // in case we got called on a geometry without orientation
        return bright;
    }
    // make sure we are on the right side of the material
    faceforward();
    OrthoNormalBasis onb = getBasis();
    Vector3 w = new Vector3();
    Color result = Color.black();
    for (int i = 0; i < samples; i++) {
        float xi = (float) getRandom(i, 0, samples);
        float xj = (float) getRandom(i, 1, samples);
        float phi = (float) (2 * Math.PI * xi);
        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(p, w);
        r.setMax(maxDist);
        result.add(Color.blend(bright, dark, traceShadow(r)));
    }
    return result.mul(1.0f / samples);
}
Also used : Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) OrthoNormalBasis(org.sunflow.math.OrthoNormalBasis)

Example 68 with Vector3

use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.

the class ShadingState method init.

/**
 * Create objects needed for surface shading: point, normal, texture
 * coordinates and basis.
 */
public final void init() {
    p = new Point3();
    n = new Vector3();
    tex = new Point2();
    ng = new Vector3();
    basis = null;
}
Also used : Point3(org.sunflow.math.Point3) Point2(org.sunflow.math.Point2) Vector3(org.sunflow.math.Vector3)

Example 69 with Vector3

use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.

the class ShadingState method specularPhong.

/**
 * Computes a phong specular response to the current light samples and
 * global illumination.
 *
 * @param spec specular color
 * @param power phong exponent
 * @param numRays number of glossy rays to trace
 * @return shaded color
 */
public final Color specularPhong(Color spec, float power, int numRays) {
    // integrate a phong specular function
    Color lr = Color.black();
    if (!includeSpecular || spec.isBlack()) {
        return lr;
    }
    // reflected direction
    float dn = 2 * cosND;
    Vector3 refDir = new Vector3();
    refDir.x = (dn * n.x) + r.dx;
    refDir.y = (dn * n.y) + r.dy;
    refDir.z = (dn * n.z) + r.dz;
    // direct lighting
    for (LightSample sample : this) {
        float cosNL = sample.dot(n);
        float cosLR = sample.dot(refDir);
        if (cosLR > 0) {
            lr.madd(cosNL * (float) Math.pow(cosLR, power), sample.getSpecularRadiance());
        }
    }
    // indirect lighting
    if (numRays > 0) {
        int numSamples = getDepth() == 0 ? numRays : 1;
        OrthoNormalBasis onb = OrthoNormalBasis.makeFromW(refDir);
        float mul = (2.0f * (float) Math.PI / (power + 1)) / numSamples;
        for (int i = 0; i < numSamples; i++) {
            // specular indirect lighting
            double r1 = getRandom(i, 0, numSamples);
            double r2 = getRandom(i, 1, numSamples);
            double u = 2 * Math.PI * r1;
            double s = (float) Math.pow(r2, 1 / (power + 1));
            double s1 = (float) Math.sqrt(1 - s * s);
            Vector3 w = new Vector3((float) (Math.cos(u) * s1), (float) (Math.sin(u) * s1), (float) s);
            w = onb.transform(w, new Vector3());
            float wn = Vector3.dot(w, n);
            if (wn > 0) {
                lr.madd(wn * mul, traceGlossy(new Ray(p, w), i));
            }
        }
    }
    lr.mul(spec).mul((power + 2) / (2.0f * (float) Math.PI));
    return lr;
}
Also used : Color(org.sunflow.image.Color) Vector3(org.sunflow.math.Vector3) OrthoNormalBasis(org.sunflow.math.OrthoNormalBasis)

Example 70 with Vector3

use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.

the class UniformGrid method build.

@Override
public void build(PrimitiveList primitives) {
    Timer t = new Timer();
    t.start();
    this.primitives = primitives;
    int n = primitives.getNumPrimitives();
    // compute bounds
    bounds = primitives.getWorldBounds(null);
    // create grid from number of objects
    bounds.enlargeUlps();
    Vector3 w = bounds.getExtents();
    double s = Math.pow((w.x * w.y * w.z) / n, 1 / 3.0);
    nx = MathUtils.clamp((int) ((w.x / s) + 0.5), 1, 128);
    ny = MathUtils.clamp((int) ((w.y / s) + 0.5), 1, 128);
    nz = MathUtils.clamp((int) ((w.z / s) + 0.5), 1, 128);
    voxelwx = w.x / nx;
    voxelwy = w.y / ny;
    voxelwz = w.z / nz;
    invVoxelwx = 1 / voxelwx;
    invVoxelwy = 1 / voxelwy;
    invVoxelwz = 1 / voxelwz;
    UI.printDetailed(Module.ACCEL, "Creating grid: %dx%dx%d ...", nx, ny, nz);
    IntArray[] buildCells = new IntArray[nx * ny * nz];
    // add all objects into the grid cells they overlap
    int[] imin = new int[3];
    int[] imax = new int[3];
    int numCellsPerObject = 0;
    for (int i = 0; i < n; i++) {
        getGridIndex(primitives.getPrimitiveBound(i, 0), primitives.getPrimitiveBound(i, 2), primitives.getPrimitiveBound(i, 4), imin);
        getGridIndex(primitives.getPrimitiveBound(i, 1), primitives.getPrimitiveBound(i, 3), primitives.getPrimitiveBound(i, 5), imax);
        for (int ix = imin[0]; ix <= imax[0]; ix++) {
            for (int iy = imin[1]; iy <= imax[1]; iy++) {
                for (int iz = imin[2]; iz <= imax[2]; iz++) {
                    int idx = ix + (nx * iy) + (nx * ny * iz);
                    if (buildCells[idx] == null) {
                        buildCells[idx] = new IntArray();
                    }
                    buildCells[idx].add(i);
                    numCellsPerObject++;
                }
            }
        }
    }
    UI.printDetailed(Module.ACCEL, "Building cells ...");
    int numEmpty = 0;
    int numInFull = 0;
    cells = new int[nx * ny * nz][];
    int i = 0;
    for (IntArray cell : buildCells) {
        if (cell != null) {
            if (cell.getSize() == 0) {
                numEmpty++;
                cell = null;
            } else {
                cells[i] = cell.trim();
                numInFull += cell.getSize();
            }
        } else {
            numEmpty++;
        }
        i++;
    }
    t.end();
    UI.printDetailed(Module.ACCEL, "Uniform grid statistics:");
    UI.printDetailed(Module.ACCEL, "  * Grid cells:          %d", cells.length);
    UI.printDetailed(Module.ACCEL, "  * Used cells:          %d", cells.length - numEmpty);
    UI.printDetailed(Module.ACCEL, "  * Empty cells:         %d", numEmpty);
    UI.printDetailed(Module.ACCEL, "  * Occupancy:           %.2f%%", 100.0 * (cells.length - numEmpty) / cells.length);
    UI.printDetailed(Module.ACCEL, "  * Objects/Cell:        %.2f", (double) numInFull / (double) cells.length);
    UI.printDetailed(Module.ACCEL, "  * Objects/Used Cell:   %.2f", (double) numInFull / (double) (cells.length - numEmpty));
    UI.printDetailed(Module.ACCEL, "  * Cells/Object:        %.2f", (double) numCellsPerObject / (double) n);
    UI.printDetailed(Module.ACCEL, "  * Build time:          %s", t.toString());
}
Also used : Timer(org.sunflow.system.Timer) IntArray(org.sunflow.util.IntArray) Vector3(org.sunflow.math.Vector3)

Aggregations

Vector3 (org.sunflow.math.Vector3)75 Color (org.sunflow.image.Color)34 Point3 (org.sunflow.math.Point3)27 Ray (org.sunflow.core.Ray)25 OrthoNormalBasis (org.sunflow.math.OrthoNormalBasis)17 Instance (org.sunflow.core.Instance)11 LightSample (org.sunflow.core.LightSample)8 ShadingState (org.sunflow.core.ShadingState)3 ParameterList (org.sunflow.core.ParameterList)2 TriangleMesh (org.sunflow.core.primitive.TriangleMesh)2 XYZColor (org.sunflow.image.XYZColor)2 Timer (org.sunflow.system.Timer)2 File (java.io.File)1 FileInputStream (java.io.FileInputStream)1 FileNotFoundException (java.io.FileNotFoundException)1 IOException (java.io.IOException)1 FloatBuffer (java.nio.FloatBuffer)1 MappedByteBuffer (java.nio.MappedByteBuffer)1 ReentrantReadWriteLock (java.util.concurrent.locks.ReentrantReadWriteLock)1 PrimitiveList (org.sunflow.core.PrimitiveList)1