public static Vector3 sub(Point3 p1, Point3 p2, Vector3 dest) { dest.x = p1.x - p2.x; dest.y = p1.y - p2.y; dest.z = p1.z - p2.z; return dest; }
public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) { double rnd = randX1 * totalArea; int j = areas.Length - 1; for (int i = 0; i < areas.Length; i++) { if (rnd < areas[i]) { j = i; break; } rnd -= areas[i]; // try next triangle } rnd /= areas[j]; randX1 = rnd; double s = Math.Sqrt(1 - randX2); float u = (float) (randY2 * s); float v = (float) (1 - s); float w = 1 - u - v; int tri3 = j * 3; int index0 = 3 * triangles[tri3 + 0]; int index1 = 3 * triangles[tri3 + 1]; int index2 = 3 * triangles[tri3 + 2]; p.x = w * points[index0 + 0] + u * points[index1 + 0] + v * points[index2 + 0]; p.y = w * points[index0 + 1] + u * points[index1 + 1] + v * points[index2 + 1]; p.z = w * points[index0 + 2] + u * points[index1 + 2] + v * points[index2 + 2]; p.x += 0.001f * ngs[j].x; p.y += 0.001f * ngs[j].y; p.z += 0.001f * ngs[j].z; OrthoNormalBasis onb = OrthoNormalBasis.makeFromW(ngs[j]); u = (float) (2 * Math.PI * randX1); s = Math.Sqrt(randY1); onb.transform(new Vector3((float) (Math.Cos(u) * s), (float) (Math.Sin(u) * s), (float) (Math.Sqrt(1 - randY1))), dir); Color.mul((float) Math.PI * areas[j], radiance, power); }
public static Point3 add(Point3 p, Vector3 v, Point3 dest) { dest.x = p.x + v.x; dest.y = p.y + v.y; dest.z = p.z + v.z; return dest; }
public void getSamples(ShadingState state) { if (Vector3.dot(dir, state.getGeoNormal()) < 0 && Vector3.dot(dir, state.getNormal()) < 0) { // project point onto source plane float x = state.getPoint().x - src.x; float y = state.getPoint().y - src.y; float z = state.getPoint().z - src.z; float t = ((x * dir.x) + (y * dir.y) + (z * dir.z)); if (t >= 0.0) { x -= (t * dir.x); y -= (t * dir.y); z -= (t * dir.z); if (((x * x) + (y * y) + (z * z)) <= r2) { Point3 p = new Point3(); p.x = src.x + x; p.y = src.y + y; p.z = src.z + z; LightSample dest = new LightSample(); dest.setShadowRay(new Ray(state.getPoint(), p)); dest.setRadiance(radiance, radiance); dest.traceShadow(state); state.addSample(dest); } } } }
public static Point3 blend(Point3 p0, Point3 p1, float blend, Point3 dest) { dest.x = (1 - blend) * p0.x + blend * p1.x; dest.y = (1 - blend) * p0.y + blend * p1.y; dest.z = (1 - blend) * p0.z + blend * p1.z; return dest; }
public static Point3 mid(Point3 p1, Point3 p2, Point3 dest) { dest.x = 0.5f * (p1.x + p2.x); dest.y = 0.5f * (p1.y + p2.y); dest.z = 0.5f * (p1.z + p2.z); return dest; }
public SphereLight() { radiance = Color.WHITE; numSamples = 4; center = new Point3(); radius = r2 = 1; }
public Color getRadiance(ShadingState state) { Point3[] p = new Point3[3]; if (!state.getTrianglePoints(p)) return getFillColor(state); // transform points into camera space Point3 center = state.getPoint(); Matrix4 w2c = state.getWorldToCamera(); center = w2c.transformP(center); for (int i = 0; i < 3; i++) p[i] = w2c.transformP(state.getInstance().transformObjectToWorld(p[i])); float cn = 1.0f / (float)Math.Sqrt(center.x * center.x + center.y * center.y + center.z * center.z); for (int i = 0, i2 = 2; i < 3; i2 = i, i++) { // compute orthogonal projection of the shading point onto each // triangle edge as in: // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html float t = (center.x - p[i].x) * (p[i2].x - p[i].x); t += (center.y - p[i].y) * (p[i2].y - p[i].y); t += (center.z - p[i].z) * (p[i2].z - p[i].z); t /= p[i].distanceToSquared(p[i2]); float projx = (1 - t) * p[i].x + t * p[i2].x; float projy = (1 - t) * p[i].y + t * p[i2].y; float projz = (1 - t) * p[i].z + t * p[i2].z; float n = 1.0f / (float)Math.Sqrt(projx * projx + projy * projy + projz * projz); // check angular width float dot = projx * center.x + projy * center.y + projz * center.z; if (dot * n * cn >= cosWidth) return getLineColor(state); } return getFillColor(state); }
public RealtimeBenchmark(bool showGUI, int threads) { IDisplay display = /*showGUI ? new FastDisplay() :*/ new FileDisplay(false); UI.printInfo(UI.Module.BENCH, "Preparing benchmarking scene ..."); // settings parameter("threads", threads); // spawn regular priority threads parameter("threads.lowPriority", false); parameter("resolutionX", 512); parameter("resolutionY", 512); parameter("aa.min", -3); parameter("aa.max", 0); parameter("depths.diffuse", 1); parameter("depths.reflection", 1); parameter("depths.refraction", 0); parameter("bucket.order", "hilbert"); parameter("bucket.size", 32); options(SunflowAPI.DEFAULT_OPTIONS); // camera Point3 eye = new Point3(30, 0, 10.967f); Point3 target = new Point3(0, 0, 5.4f); Vector3 up = new Vector3(0, 0, 1); parameter("transform", Matrix4.lookAt(eye, target, up)); parameter("fov", 45.0f); camera("camera", "pinhole"); parameter("camera", "camera"); options(SunflowAPI.DEFAULT_OPTIONS); // geometry createGeometry(); // this first render is not timed, it caches the acceleration data // structures and tesselations so they won't be // included in the main timing UI.printInfo(UI.Module.BENCH, "Rendering warmup frame ..."); render(SunflowAPI.DEFAULT_OPTIONS, display); // now disable all output - and run the benchmark UI.set(null); Timer t = new Timer(); t.start(); float phi = 0; int frames = 0; while (phi < 4 * Math.PI) { eye.x = 30 * (float)Math.Cos(phi); eye.y = 30 * (float)Math.Sin(phi); phi += (float)(Math.PI / 30); frames++; // update camera parameter("transform", Matrix4.lookAt(eye, target, up)); camera("camera", null); render(SunflowAPI.DEFAULT_OPTIONS, display); } t.end(); UI.set(new ConsoleInterface()); UI.printInfo(UI.Module.BENCH, "Benchmark results:"); UI.printInfo(UI.Module.BENCH, " * Average FPS: {0,6:0.00", frames / t.seconds()); UI.printInfo(UI.Module.BENCH, " * Total time: {0}", t); }
public Photon(Point3 p, Vector3 dir, Color power) { x = p.x; y = p.y; z = p.z; this.dir = dir.encode(); this.power = power.toRGBE(); flags = 0; }
public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) { p.set(lightPoint); float phi = (float)(2 * Math.PI * randX1); float s = (float)Math.Sqrt(randY1 * (1.0f - randY1)); dir.x = (float)Math.Cos(phi) * s; dir.y = (float)Math.Sin(phi) * s; dir.z = (float)(1 - 2 * randY1); power.set(this.power); }
public DirectionalSpotlight() { src = new Point3(0, 0, 0); dir = new Vector3(0, 0, -1); dir.normalize(); basis = OrthoNormalBasis.makeFromW(dir); r = 1; r2 = r * r; radiance = Color.WHITE; }
public Photon(Point3 p, Vector3 n, Vector3 dir, Color power, Color diffuse) { x = p.x; y = p.y; z = p.z; this.dir = dir.encode(); this.power = power.toRGBE(); flags = 0; normal = n.encode(); data = diffuse.toRGB(); }
public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) { float phi = (float)(2 * Math.PI * randX1); float s = (float)Math.Sqrt(1.0f - randY1); dir.x = r * (float)Math.Cos(phi) * s; dir.y = r * (float)Math.Sin(phi) * s; dir.z = 0; basis.transform(dir); Point3.add(src, dir, p); dir.set(this.dir); power.set(radiance).mul((float)Math.PI * r2); }
public static Vector3 normal(Point3 p0, Point3 p1, Point3 p2) { float edge1x = p1.x - p0.x; float edge1y = p1.y - p0.y; float edge1z = p1.z - p0.z; float edge2x = p2.x - p0.x; float edge2y = p2.y - p0.y; float edge2z = p2.z - p0.z; float nx = edge1y * edge2z - edge1z * edge2y; float ny = edge1z * edge2x - edge1x * edge2z; float nz = edge1x * edge2y - edge1y * edge2x; return new Vector3(nx, ny, nz); }
public static Vector3 normal(Point3 p0, Point3 p1, Point3 p2, Vector3 dest) { float edge1x = p1.x - p0.x; float edge1y = p1.y - p0.y; float edge1z = p1.z - p0.z; float edge2x = p2.x - p0.x; float edge2y = p2.y - p0.y; float edge2z = p2.z - p0.z; dest.x = edge1y * edge2z - edge1z * edge2y; dest.y = edge1z * edge2x - edge1x * edge2z; dest.z = edge1x * edge2y - edge1y * edge2x; return dest; }
/** * Creates a new ray that points from the given origin to the given * direction. The ray has infinite Length. The direction vector is * normalized. * * @param o ray origin * @param d ray direction (need not be normalized) */ public Ray(Point3 o, Vector3 d) { ox = o.x; oy = o.y; oz = o.z; dx = d.x; dy = d.y; dz = d.z; float inf = 1.0f / (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); dx *= inf; dy *= inf; dz *= inf; tMin = EPSILON; tMax = float.PositiveInfinity; }
public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) { float z = (float)(1 - 2 * randX2); float r = (float)Math.Sqrt(Math.Max(0, 1 - z * z)); float phi = (float)(2 * Math.PI * randY2); float x = r * (float)Math.Cos(phi); float y = r * (float)Math.Sin(phi); p.x = center.x + x * radius; p.y = center.y + y * radius; p.z = center.z + z * radius; OrthoNormalBasis basis = OrthoNormalBasis.makeFromW(new Vector3(x, y, z)); phi = (float)(2 * Math.PI * randX1); float cosPhi = (float)Math.Cos(phi); float sinPhi = (float)Math.Sin(phi); float sinTheta = (float)Math.Sqrt(randY1); float cosTheta = (float)Math.Sqrt(1 - randY1); dir.x = cosPhi * sinTheta; dir.y = sinPhi * sinTheta; dir.z = cosTheta; basis.transform(dir); power.set(radiance); power.mul((float)(Math.PI * Math.PI * 4 * r2)); }
public void getSamples(ShadingState state) { if (storedPhotons == 0) return; NearestPhotons np = new NearestPhotons(state.getPoint(), gatherNum, gatherRadius * gatherRadius); locatePhotons(np); if (np.found < 8) return; Point3 ppos = new Point3(); Vector3 pdir = new Vector3(); Vector3 pvec = new Vector3(); float invArea = 1.0f / ((float)Math.PI * np.dist2[0]); float maxNDist = np.dist2[0] * 0.05f; float f2r2 = 1.0f / (filterValue * filterValue * np.dist2[0]); float fInv = 1.0f / (1.0f - 2.0f / (3.0f * filterValue)); for (int i = 1; i <= np.found; i++) { Photon phot = np.index[i]; Vector3.decode(phot.dir, pdir); float cos = -Vector3.dot(pdir, state.getNormal()); if (cos > 0.001) { ppos.set(phot.x, phot.y, phot.z); Point3.sub(ppos, state.getPoint(), pvec); float pcos = Vector3.dot(pvec, state.getNormal()); if ((pcos < maxNDist) && (pcos > -maxNDist)) { LightSample sample = new LightSample(); sample.setShadowRay(new Ray(state.getPoint(), pdir.negate())); sample.setRadiance(new Color().setRGBE(np.index[i].power).mul(invArea / cos), Color.BLACK); sample.getDiffuseRadiance().mul((1.0f - (float)Math.Sqrt(np.dist2[i] * f2r2)) * fInv); state.addSample(sample); } } } }
/** * Generate a ray from the origin of camera space toward the specified * point. * * @param p point in world space * @return ray from the origin of camera space to the specified point */ public Ray getRay(Point3 p) { return new Ray(c2w == null ? new Point3(0, 0, 0) : c2w[0].transformP(new Point3(0, 0, 0)), p); }
/** * Creates a bounding box centered around the origin. * * @param size half edge Length of the bounding box */ public BoundingBox(float size) { minimum = new Point3(-size, -size, -size); maximum = new Point3(size, size, size); }
/** * Creates an empty box. The minimum point will have all components set to * positive infinity, and the maximum will have all components set to * negative infinity. */ public BoundingBox() { minimum = new Point3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); maximum = new Point3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); }
/** * Checks to see if the specified {@link org.sunflow.math.Point3 point}is * inside the volume defined by this box. Returns <code>false</code> if * the parameter is <code>null</code>. * * @param p point to be tested for containment * @return <code>true</code> if the point is inside the box, * <code>false</code> otherwise */ public bool contains(Point3 p) { return((p != null) && (p.x >= minimum.x) && (p.x <= maximum.x) && (p.y >= minimum.y) && (p.y <= maximum.y) && (p.z >= minimum.z) && (p.z <= maximum.z)); }
/** * Creates a copy of the given box. * * @param b bounding box to copy */ public BoundingBox(BoundingBox b) { minimum = new Point3(b.minimum); maximum = new Point3(b.maximum); }
/** * Creates a bounding box containing only the specified point. * * @param x x coordinate of the point to include * @param y y coordinate of the point to include * @param z z coordinate of the point to include */ public BoundingBox(float x, float y, float z) { minimum = new Point3(x, y, z); maximum = new Point3(x, y, z); }
public NearestPhotons(Point3 p, int n, float maxDist2) { max = n; found = 0; gotHeap = false; px = p.x; py = p.y; pz = p.z; dist2 = new float[n + 1]; index = new Photon[n + 1]; dist2[0] = maxDist2; }
public float distanceTo(Point3 p) { float dx = x - p.x; float dy = y - p.y; float dz = z - p.z; return (float)Math.Sqrt((dx * dx) + (dy * dy) + (dz * dz)); }
/** * Creates a bounding box containing only the specified point. * * @param p point to include */ public BoundingBox(Point3 p) : this(p.x, p.y, p.z) { }
/** * Gets the extents vector for the box. This vector is computed as (max - * min). Its coordinates are always positive and represent the dimensions of * the box along the three axes. * * @return a refreence to the extent vector * @see org.sunflow.math.Vector3#Length() */ public Vector3 getExtents() { return(Point3.sub(maximum, minimum, new Vector3())); }
public void Run() { ByteUtil.InitByteUtil(); IntersectionState istate = new IntersectionState(); for (int i = start; i < end; i++) { lock (lockObj) { UI.taskUpdate(server.photonCounter); server.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(); server.lights[j].getPhoton(randX1, randY1, randX2, randY2, pt, dir, power); power.mul(scale); Ray r = new Ray(pt, dir); server.scene.trace(r, istate); if (istate.hit()) server.shadePhoton(ShadingState.createPhotonState(r, istate, qmcI, map, server), power); } }
public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) { }
public float distanceToSquared(Point3 p) { float dx = x - p.x; float dy = y - p.y; float dz = z - p.z; return (dx * dx) + (dy * dy) + (dz * dz); }
void reset(Point3 p, float maxDist2) { found = 0; gotHeap = false; px = p.x; py = p.y; pz = p.z; dist2[0] = maxDist2; }
public Point3 set(Point3 p) { x = p.x; y = p.y; z = p.z; return this; }
public bool update(ParameterList pl, SunflowAPI api) { src = pl.getPoint("source", src); dir = pl.getVector("dir", dir); dir.normalize(); r = pl.getFloat("radius", r); basis = OrthoNormalBasis.makeFromW(dir); r2 = r * r; radiance = pl.getColor("radiance", radiance); return true; }
public Point3(Point3 p) { x = p.x; y = p.y; z = p.z; }
private TriangleMesh generate(int[] tris, float[] verts, bool smoothNormals) { ParameterList pl = new ParameterList(); pl.addIntegerArray("triangles", tris); pl.addPoints("points", ParameterList.InterpolationType.VERTEX, verts); if (smoothNormals) { float[] normals = new float[verts.Length]; // filled with 0's Point3 p0 = new Point3(); Point3 p1 = new Point3(); Point3 p2 = new Point3(); Vector3 n = new Vector3(); for (int i3 = 0; i3 < tris.Length; i3 += 3) { int v0 = tris[i3 + 0]; int v1 = tris[i3 + 1]; int v2 = tris[i3 + 2]; p0.set(verts[3 * v0 + 0], verts[3 * v0 + 1], verts[3 * v0 + 2]); p1.set(verts[3 * v1 + 0], verts[3 * v1 + 1], verts[3 * v1 + 2]); p2.set(verts[3 * v2 + 0], verts[3 * v2 + 1], verts[3 * v2 + 2]); Point3.normal(p0, p1, p2, n); // compute normal // add face normal to each vertex // note that these are not normalized so this in fact weights // each normal by the area of the triangle normals[3 * v0 + 0] += n.x; normals[3 * v0 + 1] += n.y; normals[3 * v0 + 2] += n.z; normals[3 * v1 + 0] += n.x; normals[3 * v1 + 1] += n.y; normals[3 * v1 + 2] += n.z; normals[3 * v2 + 0] += n.x; normals[3 * v2 + 1] += n.y; normals[3 * v2 + 2] += n.z; } // normalize all the vectors for (int i3 = 0; i3 < normals.Length; i3 += 3) { n.set(normals[i3 + 0], normals[i3 + 1], normals[i3 + 2]); n.normalize(); normals[i3 + 0] = n.x; normals[i3 + 1] = n.y; normals[i3 + 2] = n.z; } pl.addVectors("normals", ParameterList.InterpolationType.VERTEX, normals); } TriangleMesh m = new TriangleMesh(); if (m.update(pl, null)) return m; // something failed in creating the mesh, the error message will be // printed by the mesh itself - no need to repeat it here return null; }
/** * Gets the center of the box, computed as (min + max) / 2. * * @return a reference to the center of the box */ public Point3 getCenter() { return(Point3.mid(minimum, maximum, new Point3())); }