bool CUtils::IntersectTriangle(const CRay &i_Ray, CIntersactionInfo &io_IntersectionInfo, const CVector3DF &i_vA, const CVector3DF &i_vB, const CVector3DF &i_vC) { //intersect stuff double lambda2; double lambda3; double closestdist = io_IntersectionInfo.m_fDistance; const CVector3DF a = i_vB - i_vA; const CVector3DF b = i_vC - i_vA; CVector3DF c = - (i_Ray.Direction()); CVector3DF h = i_Ray.StartPoint() - i_vA; /* 2. Solve the equation: * * A + lambda2 * AB + lambda3 * AC = ray.start + gamma * ray.dir * * which can be rearranged as: * lambda2 * AB + lambda3 * AC - gamma * ray.dir = ray.start - A * * Which is a linear system of three rows and three unknowns, which we solve using Carmer's rule */ // // Find the determinant of the left part of the equation const float Dcr = CVector3DF::Triple(a, b, c); // check for zero; if it is zero, then the triangle and the ray are parallel if (fabs(Dcr) < k_fSMALL) { return false; } // find the reciprocal of the determinant. We would use this quantity later in order // to multiply by rDcr instead of divide by Dcr (division is much slower) double rDcr = 1.0 / Dcr; // calculate `gamma' by substituting the right part of the equation in the third column of the matrix, // getting the determinant, and dividing by Dcr) const double gamma = CVector3DF::Triple(a, b, h) * rDcr; // Is the intersection point behind us? Is the intersection point worse than what we currently have? if (gamma <= 0 || gamma > closestdist) { return false; } lambda2 = CVector3DF::Triple(h, b, c) * rDcr; // Check if it is in range (barycentric coordinates) if (lambda2 < 0 || lambda2 > 1) { return false; } lambda3 = CVector3DF::Triple(a, h, c) * rDcr; // Calculate lambda3 and check if it is in range as well if (lambda3 < 0 || lambda3 > 1) { return false; } if (lambda2 + lambda3 > 1) { return false; } closestdist = gamma; io_IntersectionInfo.m_fDistance = closestdist; io_IntersectionInfo.m_vIntersectionPoint = i_Ray.GetPointAtDistance(closestdist); io_IntersectionInfo.m_vBarCoordsLocal.SetX(1.0f - lambda2 - lambda3); io_IntersectionInfo.m_vBarCoordsLocal.SetY(lambda2); io_IntersectionInfo.m_vBarCoordsLocal.SetZ(lambda3); //Normal to the surface io_IntersectionInfo.m_vNormal = CVector3DF::Normal(a, b); return true; }
bool CBezierPatch::intersect(const CRay &ray, CIntersactionInfo &info, CVector3DF barCoord, unsigned int iterations, bool bDebug) const { //Planes along ray CVector3DF N1 = ray.Direction().Cross(CVector3DF(-1.0f,-1.0f,-1.0f)); CVector3DF N2 = ray.Direction().Cross(N1); const float d1 = -N1.Dot(ray.StartPoint()); const float d2 = -N2.Dot(ray.StartPoint()); float fSMall = 1e-3; CVector3DF dBu, dBv; for (unsigned int i = 0; i < iterations; i++) { const double &u(barCoord.X()); const double &v(barCoord.Y()); //partial U derivative of B dBu = GetdBu(u,v); //Partial V derivative of B dBv = GetdBv(u,v); const CVector3DF B = GetPointFromBarycentric(barCoord); const CVector3DF R = CVector3DF(N1.Dot(B) + d1, N2.Dot(B) + d2, 0); if ( ( fabs(R.X()) < fSMall ) && ( fabs(R.Y()) < fSMall ) ) { break; } //Inverse Jacobian const float fN1dotdBu = N1.Dot(dBu); const float fN1dotdBv = N1.Dot(dBv); const float fN2dotdBu = N2.Dot(dBu); const float fN2dotdBv = N2.Dot(dBv); const float invConst = 1.0f / ( fN1dotdBu * fN2dotdBv - fN1dotdBv * fN2dotdBu ); Matrix inverseJacobian; inverseJacobian[0][0] = fN2dotdBv * invConst; inverseJacobian[0][1] = -fN2dotdBu * invConst; inverseJacobian[0][2] = 0; inverseJacobian[1][0] = -fN1dotdBv * invConst; inverseJacobian[1][1] = fN1dotdBu * invConst; inverseJacobian[1][2] = 0; inverseJacobian[2][0] = 0; inverseJacobian[2][1] = 0; inverseJacobian[2][2] = 1; //Newton Iteration barCoord = barCoord - R.MatrixMultiply(inverseJacobian); barCoord.SetZ(1.0 - barCoord.X() - barCoord.Y()); if (barCoord.X() > k_fMAX || barCoord.X() < k_fMIN || barCoord.Y() > k_fMAX || barCoord.Y() < k_fMIN || barCoord.Z() > k_fMAX || barCoord.Z() < k_fMIN) { return false; } } const float &u(barCoord.X()); const float &v(barCoord.Y()); const float w(1.0 - u - v); if (u < -k_fSMALL || u > 1.0f + k_fSMALL || v < -k_fSMALL || v > 1.0f + k_fSMALL || w < -k_fSMALL || w > 1.0f + k_fSMALL) { return false; } if (bDebug) { char str[100]; sprintf( str, "u: %4.2f v: %4.2f w: %4.2f", u, v, w); qDebug() << str; } //Calculating B const CVector3DF B = GetPointFromBarycentric(barCoord); if ( ( fabs(N1.Dot(B) + d1) > fSMall ) || ( fabs(N2.Dot(B) + d2) > fSMall ) ) { if (bDebug) { qDebug() << "error too big"; } return false; } // calculate the intersection float len = (B - ray.StartPoint()).Length(); if (len > info.m_fDistance) { if (bDebug) { qDebug() << "Len > Distance"; } return false; } info.m_vIntersectionPoint = B; info.m_fDistance = len; info.m_vBarCoordsLocal.SetX(u); info.m_vBarCoordsLocal.SetY(v); info.m_vBarCoordsLocal.SetZ(w); info.m_vBarCoordsGlobal = info.m_vBarCoordsLocal; if (GetSettings()->m_bNormalSmoothing) { info.m_vNormal = GetSmoothedNormal(barCoord); } else { // info.m_vNormal = GetSmoothedNormal(barCoord); info.m_vNormal = CVector3DF::Normal(dBu, dBv); } if (bDebug) { qDebug()<< "Patch Hit!"; } return true; }
bool CAABox::Intersect(const CRay &ray, bool bDebug) const { if (IsInside(ray.StartPoint())) { return true; } //if (bDebug) //{ // CIntersactionInfo IntersectionInfo; // return Intersect_Test(ray, IntersectionInfo, bDebug); //} //create needed data for intersection float aRayDir[3], aRayStart[3], aRayRevDir[3], aVMin[3], aVMax[3]; for (int i = 0; i < 3; ++i) { const CVector3DF::EDimiensions eDim = (CVector3DF::EDimiensions) i; aRayDir[i] = ray.Direction().GetDimension(eDim); aRayStart[i] = ray.StartPoint().GetDimension(eDim); aVMin[i] = m_vMinVertex.GetDimension(eDim); aVMax[i] = m_vMaxVertex.GetDimension(eDim); aRayRevDir[i] = fabs(aRayDir[i]) > 1e-9 ? 1.0/ aRayDir[i] : 0.f; }; for (int dim = 0; dim < 3; dim++) { if ((aRayDir[dim] < 0 && aRayStart[dim] < aVMin[dim]) || (aRayDir[dim] > 0 && aRayStart[dim] > aVMax[dim])) { continue; } if (fabs(aRayDir[dim]) < 1e-9) { continue; } const double& mul = aRayRevDir[dim]; int u = (dim == 0) ? 1 : 0; int v = (dim == 2) ? 1 : 2; double dist, x, y; dist = (aVMin[dim] - aRayStart[dim]) * mul; if (dist < 0) { continue; } /* (*) this is a good optimization I found out by chance. Consider the following scenario * * ---+ ^ (ray) * | \ * bbox | \ * | \ * | * (camera) * -----+ * * if we're considering the walls up and down of the bbox (which belong to the same axis), * the optimization in (*) says that we can skip testing with the "up" wall, if the "down" * wall is behind us. The rationale for that is, that we can never intersect the "down" wall, * and even if we have the chance to intersect the "up" wall, we'd be intersection the "right" * wall first. So we can just skip any further intersection tests for this axis. * This may seem bogus at first, as it doesn't work if the camera is inside the BBox, but then we would * have quitted the function because of the inside(aRayStart) condition in the first line of the function. */ x = aRayStart[u] + aRayDir[u] * dist; const float fMinX = aVMin[u] - k_fSMALL; const float fMaxX = aVMax[u] + k_fSMALL; const float fMinY = aVMin[v] - k_fSMALL; const float fMaxY = aVMax[v] + k_fSMALL; if (fMinX <= x && x <= fMaxX) { y = aRayStart[v] + aRayDir[v] * dist; if (fMinY <= y && y <= fMaxY) { if ( bDebug ) { // qDebug() << "A Success Dim: "<< (EDimiensions)dim <<"X: "<< fMinX << x << fMaxX << "Y: " << fMinY << y << fMaxY; } return true; } if ( bDebug ) { // qDebug() << "A Fail Dim: "<< (EDimiensions)dim <<"X: "<< fMinX << x << fMaxX << "Y: " << fMinY << y << fMaxY; } } dist = (aVMax[dim] - aRayStart[dim]) * mul; if (dist < 0) { continue; } x = aRayStart[u] + aRayDir[u] * dist; if (fMinX <= x && x <= fMaxX) { y = aRayStart[v] + aRayDir[v] * dist; if (fMinY <= y && y <= fMaxY) { if ( bDebug ) { // qDebug() << "B Success Dim: "<< (EDimiensions)dim <<"X: "<< fMinX << x << fMaxX << "Y: " << fMinY << y << fMaxY; } return true; } if ( bDebug ) { // qDebug() << "B Fail Dim: "<< (EDimiensions)dim <<"X: "<< fMinX << x << fMaxX << "Y: " << fMinY << y << fMaxY; } } } return false; }