Exemple #1
0
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;
}
Exemple #3
0
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;
}