public void intersectPrimitive(Ray r, int primID, IntersectionState state) { // intersect in local space float rd2x = r.dx * r.dx; float rd2y = r.dy * r.dy; float rd2z = r.dz * r.dz; float ro2x = r.ox * r.ox; float ro2y = r.oy * r.oy; float ro2z = r.oz * r.oz; // setup the quartic coefficients // some common terms could probably be shared across these double A = (rd2y * rd2y + rd2z * rd2z + rd2x * rd2x); double B = 4 * (r.oy * rd2y * r.dy + r.oz * r.dz * rd2z + r.ox * r.dx * rd2x); double C = (-rd2x - rd2y - rd2z + 6 * (ro2y * rd2y + ro2z * rd2z + ro2x * rd2x)); double D = 2 * (2 * ro2z * r.oz * r.dz - r.oz * r.dz + 2 * ro2x * r.ox * r.dx + 2 * ro2y * r.oy * r.dy - r.ox * r.dx - r.oy * r.dy); double E = 3.0f / 8.0f + (-ro2z + ro2z * ro2z - ro2y + ro2y * ro2y - ro2x + ro2x * ro2x); // solve equation double[] t = Solvers.solveQuartic(A, B, C, D, E); if (t != null) { // early rejection if (t[0] >= r.getMax() || t[t.Length - 1] <= r.getMin()) return; // find first intersection in front of the ray for (int i = 0; i < t.Length; i++) { if (t[i] > r.getMin()) { r.setMax((float)t[i]); state.setIntersection(0, 0, 0); return; } } } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { // intersect in local space float qa = r.dx * r.dx + r.dy * r.dy + r.dz * r.dz; float qb = 2 * ((r.dx * r.ox) + (r.dy * r.oy) + (r.dz * r.oz)); float qc = ((r.ox * r.ox) + (r.oy * r.oy) + (r.oz * r.oz)) - 1; double[] t = Solvers.solveQuadric(qa, qb, qc); if (t != null) { // early rejection if (t[0] >= r.getMax() || t[1] <= r.getMin()) return; if (t[0] > r.getMin()) r.setMax((float)t[0]); else r.setMax((float)t[1]); state.setIntersection(0, 0, 0); } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { int i3 = primID * 3; float ocx = r.ox - particles[i3 + 0]; float ocy = r.oy - particles[i3 + 1]; float ocz = r.oz - particles[i3 + 2]; float qa = r.dx * r.dx + r.dy * r.dy + r.dz * r.dz; float qb = 2 * ((r.dx * ocx) + (r.dy * ocy) + (r.dz * ocz)); float qc = ((ocx * ocx) + (ocy * ocy) + (ocz * ocz)) - r2; double[] t = Solvers.solveQuadric(qa, qb, qc); if (t != null) { // early rejection if (t[0] >= r.getMax() || t[1] <= r.getMin()) return; if (t[0] > r.getMin()) r.setMax((float)t[0]); else r.setMax((float)t[1]); state.setIntersection(primID); } }
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.PositiveInfinity; } 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.PositiveInfinity; } 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.PositiveInfinity; } 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 bool 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); 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 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.PositiveInfinity; } 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.PositiveInfinity; } 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.PositiveInfinity; } 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) { foreach (int i in 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) { foreach (int i in 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) { foreach (int i in 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; } } }
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; // compute custom offsets from direction sign bit int offsetXFront = (int)((uint)(ByteUtil.floatToRawIntBits (dirX) & (1 << 31)) >> 30);//>>> int offsetYFront = (int)((uint)(ByteUtil.floatToRawIntBits (dirY) & (1 << 31)) >> 30);//>>> int offsetZFront = (int)((uint)(ByteUtil.floatToRawIntBits (dirZ) & (1 << 31)) >> 30);//>>> int offsetXBack = offsetXFront ^ 2; int offsetYBack = offsetYFront ^ 2; int offsetZBack = offsetZFront ^ 2; IntersectionState.StackNode[] stack = state.getStack (); int stackPos = 0; int node = 0; while (true) { int tn = tree [node]; int axis = tn & (3 << 30); int offset = tn & ~(3 << 30); switch (axis) { case 0: { float d = (ByteUtil.intBitsToFloat (tree [node + 1]) - orgX) * invDirX; int back = offset + offsetXBack; node = back; if (d < intervalMin) continue; node = offset + offsetXFront; // front if (d > intervalMax) continue; // push back node stack [stackPos].node = back; stack [stackPos].near = (d >= intervalMin) ? d : intervalMin; stack [stackPos].far = intervalMax; stackPos++; // update ray interval for front node intervalMax = (d <= intervalMax) ? d : intervalMax; continue; } case 1 << 30: { // y axis float d = (ByteUtil.intBitsToFloat (tree [node + 1]) - orgY) * invDirY; int back = offset + offsetYBack; node = back; if (d < intervalMin) continue; node = offset + offsetYFront; // front if (d > intervalMax) continue; // push back node stack [stackPos].node = back; stack [stackPos].near = (d >= intervalMin) ? d : intervalMin; stack [stackPos].far = intervalMax; stackPos++; // update ray interval for front node intervalMax = (d <= intervalMax) ? d : intervalMax; continue; } case 2 << 30: { // z axis float d = (ByteUtil.intBitsToFloat (tree [node + 1]) - orgZ) * invDirZ; int back = offset + offsetZBack; node = back; if (d < intervalMin) continue; node = offset + offsetZFront; // front if (d > intervalMax) continue; // push back node stack [stackPos].node = back; stack [stackPos].near = (d >= intervalMin) ? d : intervalMin; stack [stackPos].far = intervalMax; stackPos++; // update ray interval for front node intervalMax = (d <= intervalMax) ? d : intervalMax; continue; } default: { // leaf - test some objects int n = tree [node + 1]; while (n > 0) { primitiveList.intersectPrimitive (r, primitives [offset], state); n--; offset++; } if (r.getMax () < intervalMax) return; do { // stack is empty? if (stackPos == 0) return; // move back up the stack stackPos--; intervalMin = stack [stackPos].near; if (r.getMax () < intervalMin) continue; node = stack [stackPos].node; intervalMax = stack [stackPos].far; break; } while (true); break; } } // switch } // traversal loop }
public void intersectPrimitiveRobust(Ray r, int primID, IntersectionState state) { // ray-triangle intersection here int tri = 3 * primID; int a = 3 * triangles[tri + 0]; int b = 3 * triangles[tri + 1]; int c = 3 * triangles[tri + 2]; float[] stack = state.getRobustStack(); for (int i = 0, i3 = 0; i < 3; i++, i3 += 3) { stack[i3 + 0] = points[a + i]; stack[i3 + 1] = points[b + i]; stack[i3 + 2] = points[c + i]; } stack[9] = float.PositiveInfinity; int stackpos = 0; float orgX = r.ox; float dirX = r.dx, invDirX = 1 / dirX; float orgY = r.oy; float dirY = r.dy, invDirY = 1 / dirY; float orgZ = r.oz; float dirZ = r.dz, invDirZ = 1 / dirZ; float t1, t2; float minx, maxx; float miny, maxy; float minz, maxz; float mint = r.getMin(); float maxt = r.getMax(); while (stackpos >= 0) { float intervalMin = mint; float intervalMax = maxt; float p0x = stack[stackpos + 0]; float p1x = stack[stackpos + 1]; float p2x = stack[stackpos + 2]; t1 = ((minx = MathUtils.min(p0x, p1x, p2x)) - orgX) * invDirX; t2 = ((maxx = MathUtils.max(p0x, p1x, p2x)) - 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) { stackpos -= 10; continue; } float p0y = stack[stackpos + 3]; float p1y = stack[stackpos + 4]; float p2y = stack[stackpos + 5]; t1 = ((miny = MathUtils.min(p0y, p1y, p2y)) - orgY) * invDirY; t2 = ((maxy = MathUtils.max(p0y, p1y, p2y)) - 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) { stackpos -= 10; continue; } float p0z = stack[stackpos + 6]; float p1z = stack[stackpos + 7]; float p2z = stack[stackpos + 8]; t1 = ((minz = MathUtils.min(p0z, p1z, p2z)) - orgZ) * invDirZ; t2 = ((maxz = MathUtils.max(p0z, p1z, p2z)) - 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) { stackpos -= 10; continue; } // intersection was found - keep going float size = (maxx - minx) + (maxy - miny) + (maxz - minz); if (ByteUtil.floatToRawIntBits(stack[stackpos + 9]) == ByteUtil.floatToRawIntBits(size)) { // L1 norm is 0, we are done r.setMax(intervalMin); triaccel[primID].intersectBox(r, p0x, p0y, p0z, primID, state); return; // safe to return, only one intersection per primitive } // not small enough yet - subdivide float p01x = (p0x + p1x) * 0.5f; float p01y = (p0y + p1y) * 0.5f; float p01z = (p0z + p1z) * 0.5f; float p12x = (p1x + p2x) * 0.5f; float p12y = (p1y + p2y) * 0.5f; float p12z = (p1z + p2z) * 0.5f; float p20x = (p2x + p0x) * 0.5f; float p20y = (p2y + p0y) * 0.5f; float p20z = (p2z + p0z) * 0.5f; // triangle 0 stack[stackpos + 0] = p0x; stack[stackpos + 1] = p01x; stack[stackpos + 2] = p20x; stack[stackpos + 3] = p0y; stack[stackpos + 4] = p01y; stack[stackpos + 5] = p20y; stack[stackpos + 6] = p0z; stack[stackpos + 7] = p01z; stack[stackpos + 8] = p20z; stack[stackpos + 9] = size; stackpos += 10; // triangle 1 stack[stackpos + 0] = p1x; stack[stackpos + 1] = p12x; stack[stackpos + 2] = p01x; stack[stackpos + 3] = p1y; stack[stackpos + 4] = p12y; stack[stackpos + 5] = p01y; stack[stackpos + 6] = p1z; stack[stackpos + 7] = p12z; stack[stackpos + 8] = p01z; stack[stackpos + 9] = size; stackpos += 10; // triangle 2 stack[stackpos + 0] = p2x; stack[stackpos + 1] = p20x; stack[stackpos + 2] = p12x; stack[stackpos + 3] = p2y; stack[stackpos + 4] = p20y; stack[stackpos + 5] = p12y; stack[stackpos + 6] = p2z; stack[stackpos + 7] = p20z; stack[stackpos + 8] = p12z; stack[stackpos + 9] = size; stackpos += 10; // triangle 4 stack[stackpos + 0] = p20x; stack[stackpos + 1] = p12x; stack[stackpos + 2] = p01x; stack[stackpos + 3] = p20y; stack[stackpos + 4] = p12y; stack[stackpos + 5] = p01y; stack[stackpos + 6] = p20z; stack[stackpos + 7] = p12z; stack[stackpos + 8] = p01z; stack[stackpos + 9] = size; } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { // intersect with bounding sphere float qc = ((r.ox * r.ox) + (r.oy * r.oy) + (r.oz * r.oz)) - BOUNDING_RADIUS2; float qt = r.getMin(); if (qc > 0) { // we are starting outside the sphere, find intersection on the // sphere float qa = r.dx * r.dx + r.dy * r.dy + r.dz * r.dz; float qb = 2 * ((r.dx * r.ox) + (r.dy * r.oy) + (r.dz * r.oz)); double[] t = Solvers.solveQuadric(qa, qb, qc); // early rejection if (t == null || t[0] >= r.getMax() || t[1] <= r.getMin()) return; qt = (float)t[0]; } float dist = float.PositiveInfinity; float rox = r.ox + qt * r.dx; float roy = r.oy + qt * r.dy; float roz = r.oz + qt * r.dz; float invRayLength = (float)(1 / Math.Sqrt(r.dx * r.dx + r.dy * r.dy + r.dz * r.dz)); // now we can start intersection while (true) { float zw = rox; float zx = roy; float zy = roz; float zz = 0; float zpw = 1; float zpx = 0; float zpy = 0; float zpz = 0; // run several iterations float dotz = 0; for (int i = 0; i < maxIterations; i++) { { // zp = 2 * (z * zp) float nw = zw * zpw - zx * zpx - zy * zpy - zz * zpz; float nx = zw * zpx + zx * zpw + zy * zpz - zz * zpy; float ny = zw * zpy + zy * zpw + zz * zpx - zx * zpz; zpz = 2 * (zw * zpz + zz * zpw + zx * zpy - zy * zpx); zpw = 2 * nw; zpx = 2 * nx; zpy = 2 * ny; } { // z = z*z + c float nw = zw * zw - zx * zx - zy * zy - zz * zz + cw; zx = 2 * zw * zx + cx; zy = 2 * zw * zy + cy; zz = 2 * zw * zz + cz; zw = nw; } dotz = zw * zw + zx * zx + zy * zy + zz * zz; if (dotz > ESCAPE_THRESHOLD) break; } float normZ = (float)Math.Sqrt(dotz); dist = 0.5f * normZ * (float)Math.Log(normZ) / Length(zpw, zpx, zpy, zpz); rox += dist * r.dx; roy += dist * r.dy; roz += dist * r.dz; qt += dist; if (dist * invRayLength < epsilon) break; if (rox * rox + roy * roy + roz * roz > BOUNDING_RADIUS2) return; } // now test t value again if (!r.isInside(qt)) return; if (dist * invRayLength < epsilon) { // valid hit r.setMax(qt); state.setIntersection(0, 0, 0); } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { // intersect in local space float rd2x = r.dx * r.dx; float rd2y = r.dy * r.dy; float rd2z = r.dz * r.dz; float ro2x = r.ox * r.ox; float ro2y = r.oy * r.oy; float ro2z = r.oz * r.oz; // compute some common factors double alpha = rd2x + rd2y + rd2z; double beta = 2 * (r.ox * r.dx + r.oy * r.dy + r.oz * r.dz); double gamma = (ro2x + ro2y + ro2z) - ri2 - ro2; // setup quartic coefficients double A = alpha * alpha; double B = 2 * alpha * beta; double C = beta * beta + 2 * alpha * gamma + 4 * ro2 * rd2z; double D = 2 * beta * gamma + 8 * ro2 * r.oz * r.dz; double E = gamma * gamma + 4 * ro2 * ro2z - 4 * ro2 * ri2; // solve equation double[] t = Solvers.solveQuartic(A, B, C, D, E); if (t != null) { // early rejection if (t[0] >= r.getMax() || t[t.Length - 1] <= r.getMin()) return; // find first intersection in front of the ray for (int i = 0; i < t.Length; i++) { if (t[i] > r.getMin()) { r.setMax((float)t[i]); state.setIntersection(0, 0, 0); return; } } } }
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; // compute custom offsets from direction sign bit int offsetXFront = (int)((uint)ByteUtil.floatToRawIntBits(dirX) >> 31);//>>> int offsetYFront = (int)((uint)ByteUtil.floatToRawIntBits(dirY) >> 31);//>>> int offsetZFront = (int)((uint)ByteUtil.floatToRawIntBits(dirZ) >> 31);//>>> int offsetXBack = offsetXFront ^ 1; int offsetYBack = offsetYFront ^ 1; int offsetZBack = offsetZFront ^ 1; int offsetXFront3 = offsetXFront * 3; int offsetYFront3 = offsetYFront * 3; int offsetZFront3 = offsetZFront * 3; int offsetXBack3 = offsetXBack * 3; int offsetYBack3 = offsetYBack * 3; int offsetZBack3 = offsetZBack * 3; // avoid always adding 1 during the inner loop offsetXFront++; offsetYFront++; offsetZFront++; offsetXBack++; offsetYBack++; offsetZBack++; IntersectionState.StackNode[] stack = state.getStack(); int stackTop = state.getStackTop(); int stackPos = stackTop; int node = 0; while (true) { pushloop: while (true) { int tn = tree[node]; int axis = tn & (7 << 29); int offset = tn & ~(7 << 29); switch (axis) { case 0: { // x axis float tf = (ByteUtil.intBitsToFloat(tree[node + offsetXFront]) - orgX) * invDirX; float tb = (ByteUtil.intBitsToFloat(tree[node + offsetXBack]) - orgX) * invDirX; // ray passes between clip zones if (tf < intervalMin && tb > intervalMax) goto pushloopend; int back = offset + offsetXBack3; node = back; // ray passes through far node only if (tf < intervalMin) { intervalMin = (tb >= intervalMin) ? tb : intervalMin; continue; } node = offset + offsetXFront3; // front // ray passes through near node only if (tb > intervalMax) { intervalMax = (tf <= intervalMax) ? tf : intervalMax; continue; } // ray passes through both nodes // push back node stack[stackPos].node = back; stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin; stack[stackPos].far = intervalMax; stackPos++; // update ray interval for front node intervalMax = (tf <= intervalMax) ? tf : intervalMax; continue; } case 1 << 30: { float tf = (ByteUtil.intBitsToFloat(tree[node + offsetYFront]) - orgY) * invDirY; float tb = (ByteUtil.intBitsToFloat(tree[node + offsetYBack]) - orgY) * invDirY; // ray passes between clip zones if (tf < intervalMin && tb > intervalMax) goto pushloopend; int back = offset + offsetYBack3; node = back; // ray passes through far node only if (tf < intervalMin) { intervalMin = (tb >= intervalMin) ? tb : intervalMin; continue; } node = offset + offsetYFront3; // front // ray passes through near node only if (tb > intervalMax) { intervalMax = (tf <= intervalMax) ? tf : intervalMax; continue; } // ray passes through both nodes // push back node stack[stackPos].node = back; stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin; stack[stackPos].far = intervalMax; stackPos++; // update ray interval for front node intervalMax = (tf <= intervalMax) ? tf : intervalMax; continue; } case 2 << 30: { // z axis float tf = (ByteUtil.intBitsToFloat(tree[node + offsetZFront]) - orgZ) * invDirZ; float tb = (ByteUtil.intBitsToFloat(tree[node + offsetZBack]) - orgZ) * invDirZ; // ray passes between clip zones if (tf < intervalMin && tb > intervalMax) goto pushloopend; int back = offset + offsetZBack3; node = back; // ray passes through far node only if (tf < intervalMin) { intervalMin = (tb >= intervalMin) ? tb : intervalMin; continue; } node = offset + offsetZFront3; // front // ray passes through near node only if (tb > intervalMax) { intervalMax = (tf <= intervalMax) ? tf : intervalMax; continue; } // ray passes through both nodes // push back node stack[stackPos].node = back; stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin; stack[stackPos].far = intervalMax; stackPos++; // update ray interval for front node intervalMax = (tf <= intervalMax) ? tf : intervalMax; continue; } case 3 << 30: { // leaf - test some objects int n = tree[node + 1]; while (n > 0) { primitives.intersectPrimitive(r, objects[offset], state); n--; offset++; } goto pushloopend; } case 1 << 29: { float tf = (ByteUtil.intBitsToFloat(tree[node + offsetXFront]) - orgX) * invDirX; float tb = (ByteUtil.intBitsToFloat(tree[node + offsetXBack]) - orgX) * invDirX; node = offset; intervalMin = (tf >= intervalMin) ? tf : intervalMin; intervalMax = (tb <= intervalMax) ? tb : intervalMax; if (intervalMin > intervalMax) goto pushloopend; continue; } case 3 << 29: { float tf = (ByteUtil.intBitsToFloat(tree[node + offsetYFront]) - orgY) * invDirY; float tb = (ByteUtil.intBitsToFloat(tree[node + offsetYBack]) - orgY) * invDirY; node = offset; intervalMin = (tf >= intervalMin) ? tf : intervalMin; intervalMax = (tb <= intervalMax) ? tb : intervalMax; if (intervalMin > intervalMax) goto pushloopend; continue; } case 5 << 29: { float tf = (ByteUtil.intBitsToFloat(tree[node + offsetZFront]) - orgZ) * invDirZ; float tb = (ByteUtil.intBitsToFloat(tree[node + offsetZBack]) - orgZ) * invDirZ; node = offset; intervalMin = (tf >= intervalMin) ? tf : intervalMin; intervalMax = (tb <= intervalMax) ? tb : intervalMax; if (intervalMin > intervalMax) goto pushloopend; continue; } default: return; // should not happen } // switch } // traversal loop pushloopend: do { // stack is empty? if (stackPos == stackTop) return; // move back up the stack stackPos--; intervalMin = stack[stackPos].near; if (r.getMax() < intervalMin) continue; node = stack[stackPos].node; intervalMax = stack[stackPos].far; break; } while (true); } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { // ray patch intersection float[] stack = state.getRobustStack(); int STACKSIZE = 64; { // init patch float[] patch = patches[primID]; for (int i = 0; i < 4 * 4 * 3; i++) stack[i] = patch[i]; stack[48] = float.PositiveInfinity; // bbox size stack[49] = 0; // umin stack[50] = 0; // vmin stack[51] = 1; // umax stack[52] = 1; // vmax } int stackpos = 0; float orgX = r.ox, invDirX = 1 / r.dx; float orgY = r.oy, invDirY = 1 / r.dy; float orgZ = r.oz, invDirZ = 1 / r.dz; float t1, t2; while (stackpos >= 0) { float intervalMin = r.getMin(); float intervalMax = r.getMax(); // x-axis bbox float minx = stack[stackpos + 0]; float maxx = stack[stackpos + 0]; for (int j = 1, idx = stackpos + 3; j < 4 * 4; j++, idx += 3) { if (minx > stack[idx]) minx = stack[idx]; if (maxx < stack[idx]) maxx = stack[idx]; } t1 = (minx - orgX) * invDirX; t2 = (maxx - 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) { stackpos -= STACKSIZE; continue; } // y-axis bbox float miny = stack[stackpos + 1]; float maxy = stack[stackpos + 1]; for (int j = 1, idx = stackpos + 4; j < 4 * 4; j++, idx += 3) { if (miny > stack[idx]) miny = stack[idx]; if (maxy < stack[idx]) maxy = stack[idx]; } t1 = (miny - orgY) * invDirY; t2 = (maxy - 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) { stackpos -= STACKSIZE; continue; } // z-axis bbox float minz = stack[stackpos + 2]; float maxz = stack[stackpos + 2]; for (int j = 1, idx = stackpos + 5; j < 4 * 4; j++, idx += 3) { if (minz > stack[idx]) minz = stack[idx]; if (maxz < stack[idx]) maxz = stack[idx]; } t1 = (minz - orgZ) * invDirZ; t2 = (maxz - 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) { stackpos -= STACKSIZE; continue; } // intersection was found - keep going float size = (maxx - minx) + (maxy - miny) + (maxz - minz); if (ByteUtil.floatToRawIntBits(stack[stackpos + 48]) == ByteUtil.floatToRawIntBits(size)) { // L1 norm is 0, we are done r.setMax(intervalMin); state.setIntersection(primID, stack[stackpos + 49], stack[stackpos + 50]); stackpos -= STACKSIZE; continue; } // not small enough yet - subdivide // lets pick a subdivision axis first: float sizeu = 0; float sizev = 0; for (int i = 0; i < 3; i++) { sizeu += System.Math.Abs(stack[stackpos + (0 * 4 + 3) * 3 + i] - stack[stackpos + i]); sizev += System.Math.Abs(stack[stackpos + (3 * 4 + 0) * 3 + i] - stack[stackpos + i]); } if (sizeu > sizev) { // split in U direction for (int i = 0; i < 4; i++) { for (int axis = 0; axis < 3; axis++) { // load data float p0 = stack[stackpos + (i * 4 + 0) * 3 + axis]; float p1 = stack[stackpos + (i * 4 + 1) * 3 + axis]; float p2 = stack[stackpos + (i * 4 + 2) * 3 + axis]; float p3 = stack[stackpos + (i * 4 + 3) * 3 + axis]; // Split curve in the middle float q0 = p0; float q1 = (p0 + p1) * 0.5f; float q2 = q1 * 0.5f + (p1 + p2) * 0.25f; float r3 = p3; float r2 = (p2 + p3) * 0.5f; float r1 = r2 * 0.5f + (p1 + p2) * 0.25f; float q3 = (q2 + r1) * 0.5f; float r0 = q3; // load new curve data into the stack stack[stackpos + (i * 4 + 0) * 3 + axis] = q0; stack[stackpos + (i * 4 + 1) * 3 + axis] = q1; stack[stackpos + (i * 4 + 2) * 3 + axis] = q2; stack[stackpos + (i * 4 + 3) * 3 + axis] = q3; stack[stackpos + STACKSIZE + (i * 4 + 0) * 3 + axis] = r0; stack[stackpos + STACKSIZE + (i * 4 + 1) * 3 + axis] = r1; stack[stackpos + STACKSIZE + (i * 4 + 2) * 3 + axis] = r2; stack[stackpos + STACKSIZE + (i * 4 + 3) * 3 + axis] = r3; } } // copy current bbox size stack[stackpos + 48] = stack[stackpos + STACKSIZE + 48] = size; // finally - split uv ranges float umin = stack[stackpos + 49]; float umax = stack[stackpos + 51]; stack[stackpos + 49] = umin; stack[stackpos + STACKSIZE + 50] = stack[stackpos + 50]; stack[stackpos + 51] = stack[stackpos + STACKSIZE + 49] = (umin + umax) * 0.5f; stack[stackpos + STACKSIZE + 51] = umax; stack[stackpos + STACKSIZE + 52] = stack[stackpos + 52]; } else { // split in V direction for (int i = 0; i < 4; i++) { for (int axis = 0; axis < 3; axis++) { // load data float p0 = stack[stackpos + (0 * 4 + i) * 3 + axis]; float p1 = stack[stackpos + (1 * 4 + i) * 3 + axis]; float p2 = stack[stackpos + (2 * 4 + i) * 3 + axis]; float p3 = stack[stackpos + (3 * 4 + i) * 3 + axis]; // Split curve in the middle float q0 = p0; float q1 = (p0 + p1) * 0.5f; float q2 = q1 * 0.5f + (p1 + p2) * 0.25f; float r3 = p3; float r2 = (p2 + p3) * 0.5f; float r1 = r2 * 0.5f + (p1 + p2) * 0.25f; float q3 = (q2 + r1) * 0.5f; float r0 = q3; // load new curve data into the stack stack[stackpos + (0 * 4 + i) * 3 + axis] = q0; stack[stackpos + (1 * 4 + i) * 3 + axis] = q1; stack[stackpos + (2 * 4 + i) * 3 + axis] = q2; stack[stackpos + (3 * 4 + i) * 3 + axis] = q3; stack[stackpos + STACKSIZE + (0 * 4 + i) * 3 + axis] = r0; stack[stackpos + STACKSIZE + (1 * 4 + i) * 3 + axis] = r1; stack[stackpos + STACKSIZE + (2 * 4 + i) * 3 + axis] = r2; stack[stackpos + STACKSIZE + (3 * 4 + i) * 3 + axis] = r3; } } // copy current bbox size stack[stackpos + 48] = stack[stackpos + STACKSIZE + 48] = size; // finally - split uv ranges float vmin = stack[stackpos + 50]; float vmax = stack[stackpos + 52]; stack[stackpos + STACKSIZE + 49] = stack[stackpos + 49]; stack[stackpos + 50] = vmin; stack[stackpos + 52] = stack[stackpos + STACKSIZE + 50] = (vmin + vmax) * 0.5f; stack[stackpos + STACKSIZE + 51] = stack[stackpos + 51]; stack[stackpos + STACKSIZE + 52] = vmax; } stackpos += STACKSIZE; } }