public void IntersectPoint(Vector3 point, WorkerCallback intersectCallback) { Balance(); MDLCallback callback = new MDLCallback(intersectCallback, m_objects.ToArray(), (uint)m_objects.Count); m_tree.IntersectPoint(point, callback); }
public void IntersectRay(Ray ray, WorkerCallback intersectCallback, ref float maxDist) { Balance(); MDLCallback temp_cb = new MDLCallback(intersectCallback, m_objects.ToArray(), (uint)m_objects.Count); m_tree.IntersectRay(ray, temp_cb, ref maxDist, true); }
// Optimized verson of intersectRay function for rays with vertical directions public void IntersectZAllignedRay(Ray ray, WorkerCallback intersectCallback, ref float max_dist) { Cell cell = Cell.ComputeCell(ray.Origin.X, ray.Origin.Y); if (!cell.IsValid()) { return; } Node node = nodes[cell.x][cell.y]; if (node != null) { node.IntersectRay(ray, intersectCallback, ref max_dist); } }
public void IntersectPoint(Vector3 point, WorkerCallback intersectCallback) { Cell cell = Cell.ComputeCell(point.X, point.Y); if (!cell.IsValid()) { return; } Node node = nodes[cell.x][cell.y]; if (node != null) { node.IntersectPoint(point, intersectCallback); } }
public void IntersectRay(Ray ray, WorkerCallback intersectCallback, ref float max_dist, Vector3 end) { Cell cell = Cell.ComputeCell(ray.Origin.X, ray.Origin.Y); if (!cell.IsValid()) { return; } Cell last_cell = Cell.ComputeCell(end.X, end.Y); if (cell == last_cell) { Node node = nodes[cell.x][cell.y]; if (node != null) { node.IntersectRay(ray, intersectCallback, ref max_dist); } return; } float voxel = CELL_SIZE; float kx_inv = ray.invDirection().X, bx = ray.Origin.X; float ky_inv = ray.invDirection().Y, by = ray.Origin.Y; int stepX, stepY; float tMaxX, tMaxY; if (kx_inv >= 0) { stepX = 1; float x_border = (cell.x + 1) * voxel; tMaxX = (x_border - bx) * kx_inv; } else { stepX = -1; float x_border = (cell.x - 1) * voxel; tMaxX = (x_border - bx) * kx_inv; } if (ky_inv >= 0) { stepY = 1; float y_border = (cell.y + 1) * voxel; tMaxY = (y_border - by) * ky_inv; } else { stepY = -1; float y_border = (cell.y - 1) * voxel; tMaxY = (y_border - by) * ky_inv; } float tDeltaX = voxel * Math.Abs(kx_inv); float tDeltaY = voxel * Math.Abs(ky_inv); do { Node node = nodes[cell.x][cell.y]; if (node != null) { node.IntersectRay(ray, intersectCallback, ref max_dist); } if (cell == last_cell) { break; } if (tMaxX < tMaxY) { tMaxX += tDeltaX; cell.x += stepX; } else { tMaxY += tDeltaY; cell.y += stepY; } } while (cell.IsValid()); }
public void IntersectRay(Ray ray, WorkerCallback intersectCallback, ref float max_dist) { IntersectRay(ray, intersectCallback, ref max_dist, ray.Origin + ray.Direction * max_dist); }
public void IntersectPoint(Vector3 p, WorkerCallback intersectCallback) { if (!bounds.contains(p)) { return; } StackNode[] stack = new StackNode[64]; int stackPos = 0; int node = 0; while (true) { while (true) { uint tn = tree[node]; uint axis = (uint)(tn & (3 << 30)) >> 30; bool BVH2 = Convert.ToBoolean(tn & (1 << 29)); int offset = (int)(tn & ~(7 << 29)); if (!BVH2) { if (axis < 3) { // "normal" interior node float tl = IntBitsToFloat(tree[node + 1]); float tr = IntBitsToFloat(tree[node + 2]); // point is between clip zones if (tl < p[(int)axis] && tr > p[axis]) { break; } int right = offset + 3; node = right; // point is in right node only if (tl < p[(int)axis]) { continue; } node = offset; // left // point is in left node only if (tr > p[axis]) { continue; } // point is in both nodes // push back right node stack[stackPos].node = (uint)right; stackPos++; continue; } else { // leaf - test some objects uint n = tree[node + 1]; while (n > 0) { intersectCallback.Invoke(p, objects[offset]); // !!! --n; ++offset; } break; } } else // BVH2 node (empty space cut off left and right) { if (axis > 2) { return; // should not happen } float tl = IntBitsToFloat(tree[node + 1]); float tr = IntBitsToFloat(tree[node + 2]); node = offset; if (tl > p[axis] || tr < p[axis]) { break; } continue; } } // traversal loop // stack is empty? if (stackPos == 0) { return; } // move back up the stack stackPos--; node = (int)stack[stackPos].node; } }
public void IntersectRay(Ray r, WorkerCallback intersectCallback, ref float maxDist, bool stopAtFirst = false) { float intervalMin = -1.0f; float intervalMax = -1.0f; Vector3 org = r.Origin; Vector3 dir = r.Direction; Vector3 invDir = new(); for (int i = 0; i < 3; ++i) { invDir[i] = 1.0f / dir[i]; if (MathFunctions.fuzzyNe(dir[i], 0.0f)) { float t1 = (bounds.Lo[i] - org[i]) * invDir[i]; float t2 = (bounds.Hi[i] - org[i]) * invDir[i]; if (t1 > t2) { MathFunctions.Swap <float>(ref t1, ref t2); } if (t1 > intervalMin) { intervalMin = t1; } if (t2 < intervalMax || intervalMax < 0.0f) { intervalMax = t2; } // intervalMax can only become smaller for other axis, // and intervalMin only larger respectively, so stop early if (intervalMax <= 0 || intervalMin >= maxDist) { return; } } } if (intervalMin > intervalMax) { return; } intervalMin = Math.Max(intervalMin, 0.0f); intervalMax = Math.Min(intervalMax, maxDist); uint[] offsetFront = new uint[3]; uint[] offsetBack = new uint[3]; uint[] offsetFront3 = new uint[3]; uint[] offsetBack3 = new uint[3]; // compute custom offsets from direction sign bit for (int i = 0; i < 3; ++i) { offsetFront[i] = FloatToRawIntBits(dir[i]) >> 31; offsetBack[i] = offsetFront[i] ^ 1; offsetFront3[i] = offsetFront[i] * 3; offsetBack3[i] = offsetBack[i] * 3; // avoid always adding 1 during the inner loop ++offsetFront[i]; ++offsetBack[i]; } StackNode[] stack = new StackNode[64]; int stackPos = 0; int node = 0; while (true) { while (true) { uint tn = tree[node]; uint axis = (uint)(tn & (3 << 30)) >> 30; bool BVH2 = Convert.ToBoolean(tn & (1 << 29)); int offset = (int)(tn & ~(7 << 29)); if (!BVH2) { if (axis < 3) { // "normal" interior node float tf = (IntBitsToFloat(tree[(int)(node + offsetFront[axis])]) - org[axis]) * invDir[axis]; float tb = (IntBitsToFloat(tree[(int)(node + offsetBack[axis])]) - org[axis]) * invDir[axis]; // ray passes between clip zones if (tf < intervalMin && tb > intervalMax) { break; } int back = (int)(offset + offsetBack3[axis]); node = back; // ray passes through far node only if (tf < intervalMin) { intervalMin = (tb >= intervalMin) ? tb : intervalMin; continue; } node = offset + (int)offsetFront3[axis]; // 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 = (uint)back; stack[stackPos].tnear = (tb >= intervalMin) ? tb : intervalMin; stack[stackPos].tfar = intervalMax; stackPos++; // update ray interval for front node intervalMax = (tf <= intervalMax) ? tf : intervalMax; continue; } else { // leaf - test some objects int n = (int)tree[node + 1]; while (n > 0) { bool hit = intersectCallback.Invoke(r, objects[offset], ref maxDist, stopAtFirst); if (stopAtFirst && hit) { return; } --n; ++offset; } break; } } else { if (axis > 2) { return; // should not happen } float tf = (IntBitsToFloat(tree[(int)(node + offsetFront[axis])]) - org[axis]) * invDir[axis]; float tb = (IntBitsToFloat(tree[(int)(node + offsetBack[axis])]) - org[axis]) * invDir[axis]; node = offset; intervalMin = (tf >= intervalMin) ? tf : intervalMin; intervalMax = (tb <= intervalMax) ? tb : intervalMax; if (intervalMin > intervalMax) { break; } continue; } } // traversal loop do { // stack is empty? if (stackPos == 0) { return; } // move back up the stack stackPos--; intervalMin = stack[stackPos].tnear; if (maxDist < intervalMin) { continue; } node = (int)stack[stackPos].node; intervalMax = stack[stackPos].tfar; break; } while (true); } }
public MDLCallback(WorkerCallback callback, T[] objects_array, uint size) { objects = objects_array; _callback = callback; objects_size = size; }