// --[ Method ]--------------------------------------------------------------- // // - Class : CVector3 // - Prototype : float Angle(const CRay& ray) // // - Purpose : Returns the angle between the vector and a ray. // // --------------------------------------------------------------------------- float CVector3::Angle(const CRay& ray) const { float fAngle = Angle(ray.Direction()); if(fAngle > 90.0f) fAngle = 180.0f - fAngle; return fAngle; }
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 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; }
CPoint3D CTriangle::PlaneIntersect (CRay ray) { CPoint3D ptOfIntersection; float D, t; /*************************************************************** STRATEGY: The equation of a plane is of hte form ; Ax + By + Cz + D = 0. A, B and C come from the normal which we already have, now we have to compute D. After that we can start testing for intersection. 1. Find the factor D to complete our equation of the plane. 2. Find the value of t. given by: t = - (AX0 + BY0 + CY0 + D) / (A delX + B delY + C delZ) where X0.... are the origin of the ray and delX ....are the diff between start and end point of the ray. If the ray is normalized then t gives the distance from the origin of the ray. 3. If t is negative, triangle is behind, else multiply t to the ray to get the absolute coords of the point of intersection. ***************************************************************/ // 1. D = -1.0f * (m_vecNormal.XComponent() * m_pptVertices[0].GetX() + m_vecNormal.YComponent() * m_pptVertices[0].GetY() + m_vecNormal.ZComponent() * m_pptVertices[0].GetZ()); // 2. float numer, denom; /************************************************************ 2.1. Compute the denominator first. If it is zero, no intersection. 2.2. Compute the numerator. 2.3. Divide and negate to get t. ************************************************************/ // 2.1. denom = m_vecNormal.XComponent() * ray.Direction().XComponent() + m_vecNormal.YComponent() * ray.Direction().YComponent() + m_vecNormal.ZComponent() * ray.Direction().ZComponent(); if (denom <= 0.0f + MARGIN_OF_ERROR && denom >= 0.0f - MARGIN_OF_ERROR) { return CPoint3D (0,0,0,0); // infinity } // 2.2. numer = m_vecNormal.XComponent() * ray.Origin().GetX() + m_vecNormal.YComponent() * ray.Origin().GetY() + m_vecNormal.ZComponent() * ray.Origin().GetZ() + D; // 2.3. t = -1.0f * numer / denom; // 3. if (t < 0) { return CPoint3D (0,0,0,0); // behind us; return infinity } ptOfIntersection = ray.Origin() + (ray.Direction() * t); return ptOfIntersection; }
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; }