public void intersectBox(Ray r, float hx, float hy, float hz, int primID, IntersectionState state) { switch (k) { case 0: { float hu = hy; float hv = hz; float u = hu * bnu + hv * bnv + bnd; if (u < 0.0f) { u = 0; } float v = hu * cnu + hv * cnv + cnd; if (v < 0.0f) { v = 0; } state.setIntersection(primID, u, v); return; } case 1: { float hu = hz; float hv = hx; float u = hu * bnu + hv * bnv + bnd; if (u < 0.0f) { u = 0; } float v = hu * cnu + hv * cnv + cnd; if (v < 0.0f) { v = 0; } state.setIntersection(primID, u, v); return; } case 2: { float hu = hx; float hv = hy; float u = hu * bnu + hv * bnv + bnd; if (u < 0.0f) { u = 0; } float v = hu * cnu + hv * cnv + cnd; if (v < 0.0f) { v = 0; } state.setIntersection(primID, u, v); 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) { if (r.getMax() == float.PositiveInfinity) { state.setIntersection(0, 0, 0); } }
private void intersectTriangleKensler(Ray r, int primID, IntersectionState state) { int tri = 3 * primID; int a = 3 * triangles[tri + 0]; int b = 3 * triangles[tri + 1]; int c = 3 * triangles[tri + 2]; float edge0x = points[b + 0] - points[a + 0]; float edge0y = points[b + 1] - points[a + 1]; float edge0z = points[b + 2] - points[a + 2]; float edge1x = points[a + 0] - points[c + 0]; float edge1y = points[a + 1] - points[c + 1]; float edge1z = points[a + 2] - points[c + 2]; float nx = edge0y * edge1z - edge0z * edge1y; float ny = edge0z * edge1x - edge0x * edge1z; float nz = edge0x * edge1y - edge0y * edge1x; float v = r.dot(nx, ny, nz); float iv = 1 / v; float edge2x = points[a + 0] - r.ox; float edge2y = points[a + 1] - r.oy; float edge2z = points[a + 2] - r.oz; float va = nx * edge2x + ny * edge2y + nz * edge2z; float t = iv * va; if (!r.isInside(t)) { return; } float ix = edge2y * r.dz - edge2z * r.dy; float iy = edge2z * r.dx - edge2x * r.dz; float iz = edge2x * r.dy - edge2y * r.dx; float v1 = ix * edge1x + iy * edge1y + iz * edge1z; float beta = iv * v1; if (beta < 0) { return; } float v2 = ix * edge0x + iy * edge0y + iz * edge0z; if ((v1 + v2) * v > v * v) { return; } float gamma = iv * v2; if (gamma < 0) { return; } r.setMax(t); state.setIntersection(primID, beta, gamma); }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { float dn = normal.x * r.dx + normal.y * r.dy + normal.z * r.dz; if (dn == 0.0) { return; } float t = (((center.x - r.ox) * normal.x) + ((center.y - r.oy) * normal.y) + ((center.z - r.oz) * normal.z)) / dn; if (r.isInside(t)) { r.setMax(t); state.setIntersection(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); return; } } } }
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); return; } } } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { float intervalMin = float.NegativeInfinity; float intervalMax = float.PositiveInfinity; float orgX = r.ox; float invDirX = 1 / r.dx; float t1, t2; t1 = (minX - orgX) * invDirX; t2 = (maxX - orgX) * invDirX; int sideIn = -1, sideOut = -1; if (invDirX > 0) { if (t1 > intervalMin) { intervalMin = t1; sideIn = 0; } if (t2 < intervalMax) { intervalMax = t2; sideOut = 1; } } else { if (t2 > intervalMin) { intervalMin = t2; sideIn = 1; } if (t1 < intervalMax) { intervalMax = t1; sideOut = 0; } } if (intervalMin > intervalMax) { return; } float orgY = r.oy; float invDirY = 1 / r.dy; t1 = (minY - orgY) * invDirY; t2 = (maxY - orgY) * invDirY; if (invDirY > 0) { if (t1 > intervalMin) { intervalMin = t1; sideIn = 2; } if (t2 < intervalMax) { intervalMax = t2; sideOut = 3; } } else { if (t2 > intervalMin) { intervalMin = t2; sideIn = 3; } if (t1 < intervalMax) { intervalMax = t1; sideOut = 2; } } if (intervalMin > intervalMax) { return; } float orgZ = r.oz; float invDirZ = 1 / r.dz; t1 = (minZ - orgZ) * invDirZ; // no front wall t2 = (maxZ - orgZ) * invDirZ; if (invDirZ > 0) { if (t1 > intervalMin) { intervalMin = t1; sideIn = 4; } if (t2 < intervalMax) { intervalMax = t2; sideOut = 5; } } else { if (t2 > intervalMin) { intervalMin = t2; sideIn = 5; } if (t1 < intervalMax) { intervalMax = t1; sideOut = 4; } } if (intervalMin > intervalMax) { return; } Debug.Assert(sideIn != -1); Debug.Assert(sideOut != -1); // can't hit minY wall, there is none if (sideIn != 2 && r.isInside(intervalMin)) { r.setMax(intervalMin); state.setIntersection(sideIn); } else if (sideOut != 2 && r.isInside(intervalMax)) { r.setMax(intervalMax); state.setIntersection(sideOut); } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { float uv00 = 0, uv01 = 0, uv10 = 0, uv11 = 0, uv20 = 0, uv21 = 0; switch (triangleMesh.uvs.interp) { case ParameterList.InterpolationType.NONE: case ParameterList.InterpolationType.FACE: default: return; case ParameterList.InterpolationType.VERTEX: { int tri = 3 * primID; int index0 = triangleMesh.triangles[tri + 0]; int index1 = triangleMesh.triangles[tri + 1]; int index2 = triangleMesh.triangles[tri + 2]; int i20 = 2 * index0; int i21 = 2 * index1; int i22 = 2 * index2; float[] uvs = triangleMesh.uvs.data; uv00 = uvs[i20 + 0]; uv01 = uvs[i20 + 1]; uv10 = uvs[i21 + 0]; uv11 = uvs[i21 + 1]; uv20 = uvs[i22 + 0]; uv21 = uvs[i22 + 1]; break; } case ParameterList.InterpolationType.FACEVARYING: { int idx = (3 * primID) << 1; float[] uvs = triangleMesh.uvs.data; uv00 = uvs[idx + 0]; uv01 = uvs[idx + 1]; uv10 = uvs[idx + 2]; uv11 = uvs[idx + 3]; uv20 = uvs[idx + 4]; uv21 = uvs[idx + 5]; break; } } double edge1x = uv10 - uv00; double edge1y = uv11 - uv01; double edge2x = uv20 - uv00; double edge2y = uv21 - uv01; double pvecx = r.dy * 0 - r.dz * edge2y; double pvecy = r.dz * edge2x - r.dx * 0; double pvecz = r.dx * edge2y - r.dy * edge2x; double qvecx, qvecy, qvecz; double u, v; double det = edge1x * pvecx + edge1y * pvecy + 0 * pvecz; if (det > 0) { double tvecx = r.ox - uv00; double tvecy = r.oy - uv01; double tvecz = r.oz; u = (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz); if (u < 0.0 || u > det) { return; } qvecx = tvecy * 0 - tvecz * edge1y; qvecy = tvecz * edge1x - tvecx * 0; qvecz = tvecx * edge1y - tvecy * edge1x; v = (r.dx * qvecx + r.dy * qvecy + r.dz * qvecz); if (v < 0.0 || u + v > det) { return; } } else if (det < 0) { double tvecx = r.ox - uv00; double tvecy = r.oy - uv01; double tvecz = r.oz; u = (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz); if (u > 0.0 || u < det) { return; } qvecx = tvecy * 0 - tvecz * edge1y; qvecy = tvecz * edge1x - tvecx * 0; qvecz = tvecx * edge1y - tvecy * edge1x; v = (r.dx * qvecx + r.dy * qvecy + r.dz * qvecz); if (v > 0.0 || u + v < det) { return; } } else { return; } double inv_det = 1.0 / det; float t = (float)((edge2x * qvecx + edge2y * qvecy + 0 * qvecz) * inv_det); if (r.isInside(t)) { r.setMax(t); state.setIntersection(primID, (float)(u * inv_det), (float)(v * inv_det)); } }
public void intersect(Ray r, int primID, IntersectionState state) { switch (k) { case 0: { float det = 1.0f / (r.dx + nu * r.dy + nv * r.dz); float t = (nd - r.ox - nu * r.oy - nv * r.oz) * det; if (!r.isInside(t)) { return; } float hu = r.oy + t * r.dy; float hv = r.oz + t * r.dz; float u = hu * bnu + hv * bnv + bnd; if (u < 0.0f) { return; } float v = hu * cnu + hv * cnv + cnd; if (v < 0.0f) { return; } if (u + v > 1.0f) { return; } r.setMax(t); state.setIntersection(primID, u, v); return; } case 1: { float det = 1.0f / (r.dy + nu * r.dz + nv * r.dx); float t = (nd - r.oy - nu * r.oz - nv * r.ox) * det; if (!r.isInside(t)) { return; } float hu = r.oz + t * r.dz; float hv = r.ox + t * r.dx; float u = hu * bnu + hv * bnv + bnd; if (u < 0.0f) { return; } float v = hu * cnu + hv * cnv + cnd; if (v < 0.0f) { return; } if (u + v > 1.0f) { return; } r.setMax(t); state.setIntersection(primID, u, v); return; } case 2: { float det = 1.0f / (r.dz + nu * r.dx + nv * r.dy); float t = (nd - r.oz - nu * r.ox - nv * r.oy) * det; if (!r.isInside(t)) { return; } float hu = r.ox + t * r.dx; float hv = r.oy + t * r.dy; float u = hu * bnu + hv * bnv + bnd; if (u < 0.0f) { return; } float v = hu * cnu + hv * cnv + cnd; if (v < 0.0f) { return; } if (u + v > 1.0f) { return; } r.setMax(t); state.setIntersection(primID, u, v); return; } } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { // ray/bilinear patch intersection adapted from "Production Rendering: // Design and Implementation" by Ian Stephenson (Ed.) int quad = 4 * primID; int p0 = 3 * quads[quad + 0]; int p1 = 3 * quads[quad + 1]; int p2 = 3 * quads[quad + 2]; int p3 = 3 * quads[quad + 3]; // transform patch into Hilbert space float[] A = { points[p2 + 0] - points[p3 + 0] - points[p1 + 0] + points[p0 + 0], points[p2 + 1] - points[p3 + 1] - points[p1 + 1] + points[p0 + 1], points[p2 + 2] - points[p3 + 2] - points[p1 + 2] + points[p0 + 2] }; float[] B = { points[p1 + 0] - points[p0 + 0], points[p1 + 1] - points[p0 + 1], points[p1 + 2] - points[p0 + 2] }; float[] C = { points[p3 + 0] - points[p0 + 0], points[p3 + 1] - points[p0 + 1], points[p3 + 2] - points[p0 + 2] }; float[] R = { r.ox - points[p0 + 0], r.oy - points[p0 + 1], r.oz - points[p0 + 2] }; float[] Q = { r.dx, r.dy, r.dz }; // pick major direction float absqx = Math.Abs(r.dx); float absqy = Math.Abs(r.dy); float absqz = Math.Abs(r.dz); int X = 0, Y = 1, Z = 2; if (absqx > absqy && absqx > absqz) { // X = 0, Y = 1, Z = 2 } else if (absqy > absqz) { // X = 1, Y = 0, Z = 2 X = 1; Y = 0; } else { // X = 2, Y = 1, Z = 0 X = 2; Z = 0; } float Cxz = C[X] * Q[Z] - C[Z] * Q[X]; float Cyx = C[Y] * Q[X] - C[X] * Q[Y]; float Czy = C[Z] * Q[Y] - C[Y] * Q[Z]; float Rxz = R[X] * Q[Z] - R[Z] * Q[X]; float Ryx = R[Y] * Q[X] - R[X] * Q[Y]; float Rzy = R[Z] * Q[Y] - R[Y] * Q[Z]; float Bxy = B[X] * Q[Y] - B[Y] * Q[X]; float Byz = B[Y] * Q[Z] - B[Z] * Q[Y]; float Bzx = B[Z] * Q[X] - B[X] * Q[Z]; float a = A[X] * Byz + A[Y] * Bzx + A[Z] * Bxy; if (a == 0) { // setup for linear equation float b = B[X] * Czy + B[Y] * Cxz + B[Z] * Cyx; float c = C[X] * Rzy + C[Y] * Rxz + C[Z] * Ryx; float u = -c / b; if (u >= 0 && u <= 1) { float v = (u * Bxy + Ryx) / Cyx; if (v >= 0 && v <= 1) { float t = (B[X] * u + C[X] * v - R[X]) / Q[X]; if (r.isInside(t)) { r.setMax(t); state.setIntersection(primID, u, v); } } } } else { // setup for quadratic equation float b = A[X] * Rzy + A[Y] * Rxz + A[Z] * Ryx + B[X] * Czy + B[Y] * Cxz + B[Z] * Cyx; float c = C[X] * Rzy + C[Y] * Rxz + C[Z] * Ryx; float discrim = b * b - 4 * a * c; // reject trivial cases if (c * (a + b + c) > 0 && (discrim < 0 || a * c < 0 || b / a > 0 || b / a < -2)) { return; } // solve quadratic float q = b > 0 ? -0.5f * (b + (float)Math.Sqrt(discrim)) : -0.5f * (b - (float)Math.Sqrt(discrim)); // check first solution float Axy = A[X] * Q[Y] - A[Y] * Q[X]; float u = q / a; if (u >= 0 && u <= 1) { float d = u * Axy - Cyx; float v = -(u * Bxy + Ryx) / d; if (v >= 0 && v <= 1) { float t = (A[X] * u * v + B[X] * u + C[X] * v - R[X]) / Q[X]; if (r.isInside(t)) { r.setMax(t); state.setIntersection(primID, u, v); } } } u = c / q; if (u >= 0 && u <= 1) { float d = u * Axy - Cyx; float v = -(u * Bxy + Ryx) / d; if (v >= 0 && v <= 1) { float t = (A[X] * u * v + B[X] * u + C[X] * v - R[X]) / Q[X]; if (r.isInside(t)) { r.setMax(t); state.setIntersection(primID, u, v); } } } } }
public void intersectPrimitive(Ray r, int primID, IntersectionState state) { int hair = primID / numSegments; int line = primID % numSegments; int vRoot = hair * 3 * (numSegments + 1); int v0 = vRoot + line * 3; int v1 = v0 + 3; float vx = points[v1 + 0] - points[v0 + 0]; float vy = points[v1 + 1] - points[v0 + 1]; float vz = points[v1 + 2] - points[v0 + 2]; float ux = r.dy * vz - r.dz * vy; float uy = r.dz * vx - r.dx * vz; float uz = r.dx * vy - r.dy * vx; float nx = uy * vz - uz * vy; float ny = uz * vx - ux * vz; float nz = ux * vy - uy * vx; float tden = 1 / (nx * r.dx + ny * r.dy + nz * r.dz); float tnum = nx * (points[v0 + 0] - r.ox) + ny * (points[v0 + 1] - r.oy) + nz * (points[v0 + 2] - r.oz); float t = tnum * tden; if (r.isInside(t)) { int vn = hair * (numSegments + 1) + line; float px = r.ox + t * r.dx; float py = r.oy + t * r.dy; float pz = r.oz + t * r.dz; float qx = px - points[v0 + 0]; float qy = py - points[v0 + 1]; float qz = pz - points[v0 + 2]; float q = (vx * qx + vy * qy + vz * qz) / (vx * vx + vy * vy + vz * vz); if (q <= 0) { // don't included rounded tip at root if (line == 0) { return; } float dx = points[v0 + 0] - px; float dy = points[v0 + 1] - py; float dz = points[v0 + 2] - pz; float d2 = dx * dx + dy * dy + dz * dz; float width = getWidth(vn); if (d2 < (width * width * 0.25f)) { r.setMax(t); state.setIntersection(primID, 0, 0); } } else if (q >= 1) { float dx = points[v1 + 0] - px; float dy = points[v1 + 1] - py; float dz = points[v1 + 2] - pz; float d2 = dx * dx + dy * dy + dz * dz; float width = getWidth(vn + 1); if (d2 < (width * width * 0.25f)) { r.setMax(t); state.setIntersection(primID, 0, 1); } } else { float dx = points[v0 + 0] + q * vx - px; float dy = points[v0 + 1] + q * vy - py; float dz = points[v0 + 2] + q * vz - pz; float d2 = dx * dx + dy * dy + dz * dz; float width = (1 - q) * getWidth(vn) + q * getWidth(vn + 1); if (d2 < (width * width * 0.25f)) { r.setMax(t); state.setIntersection(primID, 0, q); } } } }
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); } }
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; } }
private void intersectFlake(Ray r, IntersectionState state, int level, float qa, float qaInv, float cx, float cy, float cz, float dx, float dy, float dz, float radius) { if (level <= 0) { // we reached the bottom - intersect sphere and bail out float vcx = cx - r.ox; float vcy = cy - r.oy; float vcz = cz - r.oz; float b = r.dx * vcx + r.dy * vcy + r.dz * vcz; float disc = b * b - qa * ((vcx * vcx + vcy * vcy + vcz * vcz) - radius * radius); if (disc > 0) { // intersects - check t values float d = (float) Math.Sqrt(disc); float t1 = (b - d) * qaInv; float t2 = (b + d) * qaInv; if (t1 >= r.getMax() || t2 <= r.getMin()) return; if (t1 > r.getMin()) r.setMax(t1); else r.setMax(t2); state.setIntersection(0, cx, cy, cz); } } else { float boundRadius = radius * (1 + boundingRadiusOffset[level]); float vcx = cx - r.ox; float vcy = cy - r.oy; float vcz = cz - r.oz; float b = r.dx * vcx + r.dy * vcy + r.dz * vcz; float vcd = (vcx * vcx + vcy * vcy + vcz * vcz); float disc = b * b - qa * (vcd - boundRadius * boundRadius); if (disc > 0) { // intersects - check t values float d = (float) Math.Sqrt(disc); float t1 = (b - d) * qaInv; float t2 = (b + d) * qaInv; if (t1 >= r.getMax() || t2 <= r.getMin()) return; // we hit the bounds, now compute intersection with the actual // leaf sphere disc = b * b - qa * (vcd - radius * radius); if (disc > 0) { d = (float) Math.Sqrt(disc); t1 = (b - d) * qaInv; t2 = (b + d) * qaInv; if (t1 >= r.getMax() || t2 <= r.getMin()) { // no hit } else { if (t1 > r.getMin()) r.setMax(t1); else r.setMax(t2); state.setIntersection(0, cx, cy, cz); } } // recursively intersect 9 other spheres // step1: compute basis around displacement vector float b1x, b1y, b1z; if (dx * dx < dy * dy && dx * dx < dz * dz) { b1x = 0; b1y = dz; b1z = -dy; } else if (dy * dy < dz * dz) { b1x = dz; b1y = 0; b1z = -dx; } else { b1x = dy; b1y = -dx; b1z = 0; } float n = 1 / (float) Math.Sqrt(b1x * b1x + b1y * b1y + b1z * b1z); b1x *= n; b1y *= n; b1z *= n; float b2x = dy * b1z - dz * b1y; float b2y = dz * b1x - dx * b1z; float b2z = dx * b1y - dy * b1x; b1x = dy * b2z - dz * b2y; b1y = dz * b2x - dx * b2z; b1z = dx * b2y - dy * b2x; // step2: generate 9 children recursively float nr = radius * (1 / 3.0f), scale = radius + nr; for (int i = 0; i < 9 * 3; i += 3) { // transform by basis float ndx = recursivePattern[i] * dx + recursivePattern[i + 1] * b1x + recursivePattern[i + 2] * b2x; float ndy = recursivePattern[i] * dy + recursivePattern[i + 1] * b1y + recursivePattern[i + 2] * b2y; float ndz = recursivePattern[i] * dz + recursivePattern[i + 1] * b1z + recursivePattern[i + 2] * b2z; // recurse ! intersectFlake(r, state, level - 1, qa, qaInv, cx + scale * ndx, cy + scale * ndy, cz + scale * ndz, ndx, ndy, ndz, nr); } } } }
private void intersectFlake(Ray r, IntersectionState state, int level, float qa, float qaInv, float cx, float cy, float cz, float dx, float dy, float dz, float radius) { if (level <= 0) { // we reached the bottom - intersect sphere and bail out float vcx = cx - r.ox; float vcy = cy - r.oy; float vcz = cz - r.oz; float b = r.dx * vcx + r.dy * vcy + r.dz * vcz; float disc = b * b - qa * ((vcx * vcx + vcy * vcy + vcz * vcz) - radius * radius); if (disc > 0) { // intersects - check t values float d = (float)Math.Sqrt(disc); float t1 = (b - d) * qaInv; float t2 = (b + d) * qaInv; if (t1 >= r.getMax() || t2 <= r.getMin()) { return; } if (t1 > r.getMin()) { r.setMax(t1); } else { r.setMax(t2); } state.setIntersection(0, cx, cy, cz); } } else { float boundRadius = radius * (1 + boundingRadiusOffset[level]); float vcx = cx - r.ox; float vcy = cy - r.oy; float vcz = cz - r.oz; float b = r.dx * vcx + r.dy * vcy + r.dz * vcz; float vcd = (vcx * vcx + vcy * vcy + vcz * vcz); float disc = b * b - qa * (vcd - boundRadius * boundRadius); if (disc > 0) { // intersects - check t values float d = (float)Math.Sqrt(disc); float t1 = (b - d) * qaInv; float t2 = (b + d) * qaInv; if (t1 >= r.getMax() || t2 <= r.getMin()) { return; } // we hit the bounds, now compute intersection with the actual // leaf sphere disc = b * b - qa * (vcd - radius * radius); if (disc > 0) { d = (float)Math.Sqrt(disc); t1 = (b - d) * qaInv; t2 = (b + d) * qaInv; if (t1 >= r.getMax() || t2 <= r.getMin()) { // no hit } else { if (t1 > r.getMin()) { r.setMax(t1); } else { r.setMax(t2); } state.setIntersection(0, cx, cy, cz); } } // recursively intersect 9 other spheres // step1: compute basis around displacement vector float b1x, b1y, b1z; if (dx * dx < dy * dy && dx * dx < dz * dz) { b1x = 0; b1y = dz; b1z = -dy; } else if (dy * dy < dz * dz) { b1x = dz; b1y = 0; b1z = -dx; } else { b1x = dy; b1y = -dx; b1z = 0; } float n = 1 / (float)Math.Sqrt(b1x * b1x + b1y * b1y + b1z * b1z); b1x *= n; b1y *= n; b1z *= n; float b2x = dy * b1z - dz * b1y; float b2y = dz * b1x - dx * b1z; float b2z = dx * b1y - dy * b1x; b1x = dy * b2z - dz * b2y; b1y = dz * b2x - dx * b2z; b1z = dx * b2y - dy * b2x; // step2: generate 9 children recursively float nr = radius * (1 / 3.0f), scale = radius + nr; for (int i = 0; i < 9 * 3; i += 3) { // transform by basis float ndx = recursivePattern[i] * dx + recursivePattern[i + 1] * b1x + recursivePattern[i + 2] * b2x; float ndy = recursivePattern[i] * dy + recursivePattern[i + 1] * b1y + recursivePattern[i + 2] * b2y; float ndz = recursivePattern[i] * dz + recursivePattern[i + 1] * b1z + recursivePattern[i + 2] * b2z; // recurse ! intersectFlake(r, state, level - 1, qa, qaInv, cx + scale * ndx, cy + scale * ndy, cz + scale * ndz, ndx, ndy, ndz, nr); } } } }
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; } } }