📄 uniformgrid.java
字号:
package org.sunflow.core.accel;
import org.sunflow.core.AccelerationStructure;
import org.sunflow.core.IntersectionState;
import org.sunflow.core.PrimitiveList;
import org.sunflow.core.Ray;
import org.sunflow.math.BoundingBox;
import org.sunflow.math.MathUtils;
import org.sunflow.math.Vector3;
import org.sunflow.system.Timer;
import org.sunflow.system.UI;
import org.sunflow.system.UI.Module;
import org.sunflow.util.IntArray;
public final class UniformGrid implements AccelerationStructure {
private int nx, ny, nz;
private PrimitiveList primitives;
private BoundingBox bounds;
private int[][] cells;
private float voxelwx, voxelwy, voxelwz;
private float invVoxelwx, invVoxelwy, invVoxelwz;
public UniformGrid() {
nx = ny = nz = 0;
bounds = null;
cells = null;
voxelwx = voxelwy = voxelwz = 0;
invVoxelwx = invVoxelwy = invVoxelwz = 0;
}
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());
}
public void intersect(Ray r, IntersectionState state) {
float intervalMin = r.getMin();
float intervalMax = r.getMax();
float orgX = r.ox;
float dirX = r.dx, invDirX = 1 / dirX;
float t1, t2;
t1 = (bounds.getMinimum().x - orgX) * invDirX;
t2 = (bounds.getMaximum().x - orgX) * invDirX;
if (invDirX > 0) {
if (t1 > intervalMin)
intervalMin = t1;
if (t2 < intervalMax)
intervalMax = t2;
} else {
if (t2 > intervalMin)
intervalMin = t2;
if (t1 < intervalMax)
intervalMax = t1;
}
if (intervalMin > intervalMax)
return;
float orgY = r.oy;
float dirY = r.dy, invDirY = 1 / dirY;
t1 = (bounds.getMinimum().y - orgY) * invDirY;
t2 = (bounds.getMaximum().y - orgY) * invDirY;
if (invDirY > 0) {
if (t1 > intervalMin)
intervalMin = t1;
if (t2 < intervalMax)
intervalMax = t2;
} else {
if (t2 > intervalMin)
intervalMin = t2;
if (t1 < intervalMax)
intervalMax = t1;
}
if (intervalMin > intervalMax)
return;
float orgZ = r.oz;
float dirZ = r.dz, invDirZ = 1 / dirZ;
t1 = (bounds.getMinimum().z - orgZ) * invDirZ;
t2 = (bounds.getMaximum().z - orgZ) * invDirZ;
if (invDirZ > 0) {
if (t1 > intervalMin)
intervalMin = t1;
if (t2 < intervalMax)
intervalMax = t2;
} else {
if (t2 > intervalMin)
intervalMin = t2;
if (t1 < intervalMax)
intervalMax = t1;
}
if (intervalMin > intervalMax)
return;
// box is hit at [intervalMin, intervalMax]
orgX += intervalMin * dirX;
orgY += intervalMin * dirY;
orgZ += intervalMin * dirZ;
// locate starting point inside the grid
// and set up 3D-DDA vars
int indxX, indxY, indxZ;
int stepX, stepY, stepZ;
int stopX, stopY, stopZ;
float deltaX, deltaY, deltaZ;
float tnextX, tnextY, tnextZ;
// stepping factors along X
indxX = (int) ((orgX - bounds.getMinimum().x) * invVoxelwx);
if (indxX < 0)
indxX = 0;
else if (indxX >= nx)
indxX = nx - 1;
if (Math.abs(dirX) < 1e-6f) {
stepX = 0;
stopX = indxX;
deltaX = 0;
tnextX = Float.POSITIVE_INFINITY;
} else if (dirX > 0) {
stepX = 1;
stopX = nx;
deltaX = voxelwx * invDirX;
tnextX = intervalMin + ((indxX + 1) * voxelwx + bounds.getMinimum().x - orgX) * invDirX;
} else {
stepX = -1;
stopX = -1;
deltaX = -voxelwx * invDirX;
tnextX = intervalMin + (indxX * voxelwx + bounds.getMinimum().x - orgX) * invDirX;
}
// stepping factors along Y
indxY = (int) ((orgY - bounds.getMinimum().y) * invVoxelwy);
if (indxY < 0)
indxY = 0;
else if (indxY >= ny)
indxY = ny - 1;
if (Math.abs(dirY) < 1e-6f) {
stepY = 0;
stopY = indxY;
deltaY = 0;
tnextY = Float.POSITIVE_INFINITY;
} else if (dirY > 0) {
stepY = 1;
stopY = ny;
deltaY = voxelwy * invDirY;
tnextY = intervalMin + ((indxY + 1) * voxelwy + bounds.getMinimum().y - orgY) * invDirY;
} else {
stepY = -1;
stopY = -1;
deltaY = -voxelwy * invDirY;
tnextY = intervalMin + (indxY * voxelwy + bounds.getMinimum().y - orgY) * invDirY;
}
// stepping factors along Z
indxZ = (int) ((orgZ - bounds.getMinimum().z) * invVoxelwz);
if (indxZ < 0)
indxZ = 0;
else if (indxZ >= nz)
indxZ = nz - 1;
if (Math.abs(dirZ) < 1e-6f) {
stepZ = 0;
stopZ = indxZ;
deltaZ = 0;
tnextZ = Float.POSITIVE_INFINITY;
} else if (dirZ > 0) {
stepZ = 1;
stopZ = nz;
deltaZ = voxelwz * invDirZ;
tnextZ = intervalMin + ((indxZ + 1) * voxelwz + bounds.getMinimum().z - orgZ) * invDirZ;
} else {
stepZ = -1;
stopZ = -1;
deltaZ = -voxelwz * invDirZ;
tnextZ = intervalMin + (indxZ * voxelwz + bounds.getMinimum().z - orgZ) * invDirZ;
}
int cellstepX = stepX;
int cellstepY = stepY * nx;
int cellstepZ = stepZ * ny * nx;
int cell = indxX + indxY * nx + indxZ * ny * nx;
// trace through the grid
for (;;) {
if (tnextX < tnextY && tnextX < tnextZ) {
if (cells[cell] != null) {
for (int i : cells[cell])
primitives.intersectPrimitive(r, i, state);
if (state.hit() && (r.getMax() < tnextX && r.getMax() < intervalMax))
return;
}
intervalMin = tnextX;
if (intervalMin > intervalMax)
return;
indxX += stepX;
if (indxX == stopX)
return;
tnextX += deltaX;
cell += cellstepX;
} else if (tnextY < tnextZ) {
if (cells[cell] != null) {
for (int i : cells[cell])
primitives.intersectPrimitive(r, i, state);
if (state.hit() && (r.getMax() < tnextY && r.getMax() < intervalMax))
return;
}
intervalMin = tnextY;
if (intervalMin > intervalMax)
return;
indxY += stepY;
if (indxY == stopY)
return;
tnextY += deltaY;
cell += cellstepY;
} else {
if (cells[cell] != null) {
for (int i : cells[cell])
primitives.intersectPrimitive(r, i, state);
if (state.hit() && (r.getMax() < tnextZ && r.getMax() < intervalMax))
return;
}
intervalMin = tnextZ;
if (intervalMin > intervalMax)
return;
indxZ += stepZ;
if (indxZ == stopZ)
return;
tnextZ += deltaZ;
cell += cellstepZ;
}
}
}
private void getGridIndex(float x, float y, float z, int[] i) {
i[0] = MathUtils.clamp((int) ((x - bounds.getMinimum().x) * invVoxelwx), 0, nx - 1);
i[1] = MathUtils.clamp((int) ((y - bounds.getMinimum().y) * invVoxelwy), 0, ny - 1);
i[2] = MathUtils.clamp((int) ((z - bounds.getMinimum().z) * invVoxelwz), 0, nz - 1);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -