📄 cubegrid.java
字号:
package org.sunflow.core.primitive;
import org.sunflow.SunflowAPI;
import org.sunflow.core.Instance;
import org.sunflow.core.IntersectionState;
import org.sunflow.core.ParameterList;
import org.sunflow.core.PrimitiveList;
import org.sunflow.core.Ray;
import org.sunflow.core.ShadingState;
import org.sunflow.math.BoundingBox;
import org.sunflow.math.Matrix4;
import org.sunflow.math.OrthoNormalBasis;
import org.sunflow.math.Vector3;
public abstract class CubeGrid implements PrimitiveList {
private int nx, ny, nz;
private float voxelwx, voxelwy, voxelwz;
private float invVoxelwx, invVoxelwy, invVoxelwz;
private BoundingBox bounds;
public CubeGrid() {
nx = ny = nz = 1;
bounds = new BoundingBox(1);
}
public boolean update(ParameterList pl, SunflowAPI api) {
nx = pl.getInt("resolutionX", nx);
ny = pl.getInt("resolutionY", ny);
nz = pl.getInt("resolutionZ", nz);
voxelwx = 2.0f / nx;
voxelwy = 2.0f / ny;
voxelwz = 2.0f / nz;
invVoxelwx = 1 / voxelwx;
invVoxelwy = 1 / voxelwy;
invVoxelwz = 1 / voxelwz;
return true;
}
protected abstract boolean inside(int x, int y, int z);
public BoundingBox getBounds() {
return bounds;
}
public void prepareShadingState(ShadingState state) {
state.init();
state.getRay().getPoint(state.getPoint());
Instance parent = state.getInstance();
Vector3 normal;
switch (state.getPrimitiveID()) {
case 0:
normal = new Vector3(-1, 0, 0);
break;
case 1:
normal = new Vector3(1, 0, 0);
break;
case 2:
normal = new Vector3(0, -1, 0);
break;
case 3:
normal = new Vector3(0, 1, 0);
break;
case 4:
normal = new Vector3(0, 0, -1);
break;
case 5:
normal = new Vector3(0, 0, 1);
break;
default:
normal = new Vector3(0, 0, 0);
break;
}
state.getNormal().set(parent.transformNormalObjectToWorld(normal));
state.getGeoNormal().set(state.getNormal());
state.setBasis(OrthoNormalBasis.makeFromW(state.getNormal()));
state.setShader(parent.getShader(0));
state.setModifier(parent.getModifier(0));
}
public void intersectPrimitive(Ray r, int primID, IntersectionState state) {
float intervalMin = r.getMin();
float intervalMax = r.getMax();
float orgX = r.ox;
float orgY = r.oy;
float orgZ = r.oz;
float dirX = r.dx, invDirX = 1 / dirX;
float dirY = r.dy, invDirY = 1 / dirY;
float dirZ = r.dz, invDirZ = 1 / dirZ;
float t1, t2;
t1 = (-1 - orgX) * invDirX;
t2 = (+1 - orgX) * invDirX;
int curr = -1;
if (invDirX > 0) {
if (t1 > intervalMin) {
intervalMin = t1;
curr = 0;
}
if (t2 < intervalMax)
intervalMax = t2;
if (intervalMin > intervalMax)
return;
} else {
if (t2 > intervalMin) {
intervalMin = t2;
curr = 1;
}
if (t1 < intervalMax)
intervalMax = t1;
if (intervalMin > intervalMax)
return;
}
t1 = (-1 - orgY) * invDirY;
t2 = (+1 - orgY) * invDirY;
if (invDirY > 0) {
if (t1 > intervalMin) {
intervalMin = t1;
curr = 2;
}
if (t2 < intervalMax)
intervalMax = t2;
if (intervalMin > intervalMax)
return;
} else {
if (t2 > intervalMin) {
intervalMin = t2;
curr = 3;
}
if (t1 < intervalMax)
intervalMax = t1;
if (intervalMin > intervalMax)
return;
}
t1 = (-1 - orgZ) * invDirZ;
t2 = (+1 - orgZ) * invDirZ;
if (invDirZ > 0) {
if (t1 > intervalMin) {
intervalMin = t1;
curr = 4;
}
if (t2 < intervalMax)
intervalMax = t2;
if (intervalMin > intervalMax)
return;
} else {
if (t2 > intervalMin) {
intervalMin = t2;
curr = 5;
}
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 + 1) * 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 - 1 - orgX) * invDirX;
} else {
stepX = -1;
stopX = -1;
deltaX = -voxelwx * invDirX;
tnextX = intervalMin + (indxX * voxelwx - 1 - orgX) * invDirX;
}
// stepping factors along Y
indxY = (int) ((orgY + 1) * 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 - 1 - orgY) * invDirY;
} else {
stepY = -1;
stopY = -1;
deltaY = -voxelwy * invDirY;
tnextY = intervalMin + (indxY * voxelwy - 1 - orgY) * invDirY;
}
// stepping factors along Z
indxZ = (int) ((orgZ + 1) * 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 - 1 - orgZ) * invDirZ;
} else {
stepZ = -1;
stopZ = -1;
deltaZ = -voxelwz * invDirZ;
tnextZ = intervalMin + (indxZ * voxelwz - 1 - orgZ) * invDirZ;
}
// are we starting inside the cube
boolean isInside = inside(indxX, indxY, indxZ) && bounds.contains(r.ox, r.oy, r.oz);
// trace through the grid
for (;;) {
if (inside(indxX, indxY, indxZ) != isInside) {
// we hit a boundary
r.setMax(intervalMin);
// if we are inside, the last bit needs to be flipped
if (isInside)
curr ^= 1;
state.setIntersection(curr, 0, 0);
return;
}
if (tnextX < tnextY && tnextX < tnextZ) {
curr = dirX > 0 ? 0 : 1;
intervalMin = tnextX;
if (intervalMin > intervalMax)
return;
indxX += stepX;
if (indxX == stopX)
return;
tnextX += deltaX;
} else if (tnextY < tnextZ) {
curr = dirY > 0 ? 2 : 3;
intervalMin = tnextY;
if (intervalMin > intervalMax)
return;
indxY += stepY;
if (indxY == stopY)
return;
tnextY += deltaY;
} else {
curr = dirZ > 0 ? 4 : 5;
intervalMin = tnextZ;
if (intervalMin > intervalMax)
return;
indxZ += stepZ;
if (indxZ == stopZ)
return;
tnextZ += deltaZ;
}
}
}
public int getNumPrimitives() {
return 1;
}
public float getPrimitiveBound(int primID, int i) {
return ((i & 1) == 0) ? -1 : 1;
}
public BoundingBox getWorldBounds(Matrix4 o2w) {
if (o2w == null)
return bounds;
return o2w.transform(bounds);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -