private void growPhotonHash() { // enlarge the hash size: if (hashPrime >= PRIMES.Length - 1) { return; } PhotonGroup[] temp = new PhotonGroup[PRIMES[++hashPrime]]; for (int i = 0; i < cellHash.Length; i++) { PhotonGroup g = cellHash[i]; while (g != null) { // re-hash into the new table int hid = g.id % temp.Length; PhotonGroup last = null; for (PhotonGroup gn = temp[hid]; gn != null; gn = gn.next) { last = gn; } if (last == null) { temp[hid] = g; } else { last.next = g; } PhotonGroup next = g.next; g.next = null; g = next; } } cellHash = temp; }
public PhotonGroup(int id, Vector3 n) { normal = new Vector3(n); flux = Color.black(); diffuse = Color.black(); radiance = null; count = 0; this.id = id; next = null; }
public void init() { UI.printInfo(UI.Module.LIGHT, "Initializing photon grid ..."); UI.printInfo(UI.Module.LIGHT, " * Photon hits: %d", numStoredPhotons); UI.printInfo(UI.Module.LIGHT, " * hash size: %d", cellHash.Length); int cells = 0; for (int i = 0; i < cellHash.Length; i++) { for (PhotonGroup g = cellHash[i]; g != null; g = g.next) { g.diffuse.mul(1.0f / g.count); cells++; } } UI.printInfo(UI.Module.LIGHT, " * Num photon cells: %d", cells); }
public Color getRadiance(Point3 p, Vector3 n) { lock (lockObj) { if (!bounds.contains(p)) return Color.BLACK; Vector3 ext = bounds.getExtents(); int ix = (int)(((p.x - bounds.getMinimum().x) * nx) / ext.x); int iy = (int)(((p.y - bounds.getMinimum().y) * ny) / ext.y); int iz = (int)(((p.z - bounds.getMinimum().z) * nz) / ext.z); ix = MathUtils.clamp(ix, 0, nx - 1); iy = MathUtils.clamp(iy, 0, ny - 1); iz = MathUtils.clamp(iz, 0, nz - 1); int id = ix + iy * nx + iz * nx * ny; //rwl.readLock().lockwoot();//fixme: PhotonGroup center = null; for (PhotonGroup g = get(ix, iy, iz); g != null; g = g.next) { if (g.id == id && Vector3.dot(n, g.normal) > NORMAL_THRESHOLD) { if (g.radiance == null) { center = g; break; } Color r = g.radiance.copy(); //rwl.readLock().unlock(); return r; } } int vol = 1; while (true) { int numPhotons = 0; int ndiff = 0; Color irr = Color.black(); Color diff = (center == null) ? Color.black() : null; for (int z = iz - (vol - 1); z <= iz + (vol - 1); z++) { for (int y = iy - (vol - 1); y <= iy + (vol - 1); y++) { for (int x = ix - (vol - 1); x <= ix + (vol - 1); x++) { int vid = x + y * nx + z * nx * ny; for (PhotonGroup g = get(x, y, z); g != null; g = g.next) { if (g.id == vid && Vector3.dot(n, g.normal) > NORMAL_THRESHOLD) { numPhotons += g.count; irr.add(g.flux); if (diff != null) { diff.add(g.diffuse); ndiff++; } break; // only one valid group can be found, // skip the others } } } } } if (numPhotons >= numGather || vol >= 3) { // we have found enough photons // cache irradiance and return float area = (2 * vol - 1) / 3.0f * ((ext.x / nx) + (ext.y / ny) + (ext.z / nz)); area *= area; area *= (float)Math.PI; irr.mul(1.0f / area); // upgrade lock manually //rwl.readLock().unlock(); //rwl.writeLock().lockwoot();//fixme: if (center == null) { if (ndiff > 0) diff.mul(1.0f / ndiff); center = new PhotonGroup(id, n); center.diffuse.set(diff); center.next = cellHash[id % cellHash.Length]; cellHash[id % cellHash.Length] = center; } irr.mul(center.diffuse); center.radiance = irr.copy(); //rwl.writeLock().unlock(); // unlock write - done return irr; } vol++; } } }
private void growPhotonHash() { // enlarge the hash size: if (hashPrime >= PRIMES.Length - 1) return; PhotonGroup[] temp = new PhotonGroup[PRIMES[++hashPrime]]; for (int i = 0; i < cellHash.Length; i++) { PhotonGroup g = cellHash[i]; while (g != null) { // re-hash into the new table int hid = g.id % temp.Length; PhotonGroup last = null; for (PhotonGroup gn = temp[hid]; gn != null; gn = gn.next) last = gn; if (last == null) temp[hid] = g; else last.next = g; PhotonGroup next = g.next; g.next = null; g = next; } } cellHash = temp; }
public void store(ShadingState state, Vector3 dir, Color power, Color diffuse) { // don't store on the wrong side of a surface if (Vector3.dot(state.getNormal(), dir) > 0) return; Point3 pt = state.getPoint(); // outside grid bounds ? if (!bounds.contains(pt)) return; Vector3 ext = bounds.getExtents(); int ix = (int)(((pt.x - bounds.getMinimum().x) * nx) / ext.x); int iy = (int)(((pt.y - bounds.getMinimum().y) * ny) / ext.y); int iz = (int)(((pt.z - bounds.getMinimum().z) * nz) / ext.z); ix = MathUtils.clamp(ix, 0, nx - 1); iy = MathUtils.clamp(iy, 0, ny - 1); iz = MathUtils.clamp(iz, 0, nz - 1); int id = ix + iy * nx + iz * nx * ny; lock (lockObj) { int hid = id % cellHash.Length; PhotonGroup g = cellHash[hid]; PhotonGroup last = null; bool hasID = false; while (g != null) { if (g.id == id) { hasID = true; if (Vector3.dot(state.getNormal(), g.normal) > NORMAL_THRESHOLD) break; } last = g; g = g.next; } if (g == null) { g = new PhotonGroup(id, state.getNormal()); if (last == null) cellHash[hid] = g; else last.next = g; if (!hasID) { hashSize++; // we have not seen this ID before // resize hash if we have grown too large if (hashSize > cellHash.Length) growPhotonHash(); } } g.count++; g.flux.add(power); g.diffuse.add(diffuse); numStoredPhotons++; } }
public void store(ShadingState state, Vector3 dir, Color power, Color diffuse) { // don't store on the wrong side of a surface if (Vector3.dot(state.getNormal(), dir) > 0) { return; } Point3 pt = state.getPoint(); // outside grid bounds ? if (!bounds.contains(pt)) { return; } Vector3 ext = bounds.getExtents(); int ix = (int)(((pt.x - bounds.getMinimum().x) * nx) / ext.x); int iy = (int)(((pt.y - bounds.getMinimum().y) * ny) / ext.y); int iz = (int)(((pt.z - bounds.getMinimum().z) * nz) / ext.z); ix = MathUtils.clamp(ix, 0, nx - 1); iy = MathUtils.clamp(iy, 0, ny - 1); iz = MathUtils.clamp(iz, 0, nz - 1); int id = ix + iy * nx + iz * nx * ny; lock (lockObj) { int hid = id % cellHash.Length; PhotonGroup g = cellHash[hid]; PhotonGroup last = null; bool hasID = false; while (g != null) { if (g.id == id) { hasID = true; if (Vector3.dot(state.getNormal(), g.normal) > NORMAL_THRESHOLD) { break; } } last = g; g = g.next; } if (g == null) { g = new PhotonGroup(id, state.getNormal()); if (last == null) { cellHash[hid] = g; } else { last.next = g; } if (!hasID) { hashSize++; // we have not seen this ID before // resize hash if we have grown too large if (hashSize > cellHash.Length) { growPhotonHash(); } } } g.count++; g.flux.add(power); g.diffuse.add(diffuse); numStoredPhotons++; } }
public Color getRadiance(Point3 p, Vector3 n) { lock (lockObj) { if (!bounds.contains(p)) { return(Color.BLACK); } Vector3 ext = bounds.getExtents(); int ix = (int)(((p.x - bounds.getMinimum().x) * nx) / ext.x); int iy = (int)(((p.y - bounds.getMinimum().y) * ny) / ext.y); int iz = (int)(((p.z - bounds.getMinimum().z) * nz) / ext.z); ix = MathUtils.clamp(ix, 0, nx - 1); iy = MathUtils.clamp(iy, 0, ny - 1); iz = MathUtils.clamp(iz, 0, nz - 1); int id = ix + iy * nx + iz * nx * ny; //rwl.readLock().lockwoot();//fixme: PhotonGroup center = null; for (PhotonGroup g = get(ix, iy, iz); g != null; g = g.next) { if (g.id == id && Vector3.dot(n, g.normal) > NORMAL_THRESHOLD) { if (g.radiance == null) { center = g; break; } Color r = g.radiance.copy(); //rwl.readLock().unlock(); return(r); } } int vol = 1; while (true) { int numPhotons = 0; int ndiff = 0; Color irr = Color.black(); Color diff = (center == null) ? Color.black() : null; for (int z = iz - (vol - 1); z <= iz + (vol - 1); z++) { for (int y = iy - (vol - 1); y <= iy + (vol - 1); y++) { for (int x = ix - (vol - 1); x <= ix + (vol - 1); x++) { int vid = x + y * nx + z * nx * ny; for (PhotonGroup g = get(x, y, z); g != null; g = g.next) { if (g.id == vid && Vector3.dot(n, g.normal) > NORMAL_THRESHOLD) { numPhotons += g.count; irr.add(g.flux); if (diff != null) { diff.add(g.diffuse); ndiff++; } break; // only one valid group can be found, // skip the others } } } } } if (numPhotons >= numGather || vol >= 3) { // we have found enough photons // cache irradiance and return float area = (2 * vol - 1) / 3.0f * ((ext.x / nx) + (ext.y / ny) + (ext.z / nz)); area *= area; area *= (float)Math.PI; irr.mul(1.0f / area); // upgrade lock manually //rwl.readLock().unlock(); //rwl.writeLock().lockwoot();//fixme: if (center == null) { if (ndiff > 0) { diff.mul(1.0f / ndiff); } center = new PhotonGroup(id, n); center.diffuse.set(diff); center.next = cellHash[id % cellHash.Length]; cellHash[id % cellHash.Length] = center; } irr.mul(center.diffuse); center.radiance = irr.copy(); //rwl.writeLock().unlock(); // unlock write - done return(irr); } vol++; } } }