//----------------------------------------------------------------------------
bool ConvexPolyhedron::ComputeSilhouette (vector<Vector3>& rkTerminator,
        const Vector3& rkEye, const Plane& rkPlane, const Vector3& rkU,
        const Vector3& rkV, vector<Vector2>& rkSilhouette)
{
    Real fEDist = rkPlane.DistanceTo(rkEye);  // assert:  fEDist > 0

    // closest planar point to E is K = E-dist*N
    Vector3 kClosest = rkEye - fEDist*rkPlane.Normal();

    // project polyhedron points onto plane
    for (int i = 0; i < (int)rkTerminator.size(); i++)
    {
        Vector3& rkPoint = rkTerminator[i];

        Real fVDist = rkPlane.DistanceTo(rkPoint);
        if ( fVDist >= fEDist )
        {
            // cannot project vertex onto plane
            return false;
        }

        // compute projected point Q
        Real fRatio = fEDist/(fEDist-fVDist);
        Vector3 kProjected = rkEye + fRatio*(rkPoint - rkEye);

        // compute (x,y) so that Q = K+x*U+y*V+z*N
        Vector3 kDiff = kProjected - kClosest;
        rkSilhouette.push_back(Vector2(rkU.Dot(kDiff),rkV.Dot(kDiff)));
    }

    return true;
}
Example #2
0
// Works for either side of a plane; this wasn't always the case
bool Segment::Intersects( const Plane& p, CollisionInfo* const pInfo /*=NULL*/ ) const
{
	Vector ab = m_Point2 - m_Point1;
	float d = ab.Dot( p.m_Normal );
	if( Abs( d ) > EPSILON )	// Is segment not parallel to the plane?
	{
		// Test the t-value where the line crosses the plane to see if the
		// segment intersects or lies completely on one side (accounting
		// for the possibility that the segment faces the other way now).
		float t = -p.DistanceTo( m_Point1 ) / d;

		if( t >= 0.0f && t <= 1.0f )
		{
			if( pInfo )
			{
				pInfo->m_Collision		= true;
				pInfo->m_Intersection	= m_Point1 + t * ab;
				pInfo->m_Plane			= p;
				pInfo->m_HitT			= t;
			}
			return true;
		}
	}
	return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MLRIndexedPolyMesh::FindBackFace(const Point3D& u)
{
	Check_Object(this);

	int i, numPrimitives = GetNumPrimitives();
	int ret = 0, len = lengths.GetLength();
	unsigned char *iPtr;
	Plane *p;

	if(len <= 0)
	{
		visible = 0;

		return 0;
	}

	p = &facePlanes[0];
	iPtr = &testList[0];

	if(state.GetBackFaceMode() == MLRState::BackFaceOffMode)
	{
		ResetTestList();
		ret = 1;
	}
	else
	{
		for(i=0;i<numPrimitives;i++,p++,iPtr++)
		{
//			Scalar s = p->DistanceTo(u);

//			*iPtr = !Get_Sign_Bit(s);

			*iPtr = (p->DistanceTo(u) >= 0.0f) ? (unsigned char)1: (unsigned char)0;
			
			ret += *iPtr;
		}

		visible = ret ? (unsigned char)1 : (unsigned char)0;
	}

	visible = ret ? (unsigned char)1 : (unsigned char)0;

	FindVisibleVertices();

	return ret;
}
//----------------------------------------------------------------------------
static void SplitAndDecompose (Tetrahedron kTetra, const Plane& rkPlane,
    vector<Tetrahedron>& rkInside)
{
    // determine on which side of the plane the points of the tetrahedron lie
    Real afC[4];
    int i, aiP[4], aiN[4], aiZ[4];
    int iPositive = 0, iNegative = 0, iZero = 0;

    for (i = 0; i < 4; i++)
    {
        afC[i] = rkPlane.DistanceTo(kTetra[i]);
        if ( afC[i] > 0.0f )
            aiP[iPositive++] = i;
        else if ( afC[i] < 0.0f )
            aiN[iNegative++] = i;
        else
            aiZ[iZero++] = i;
    }

    // For a split to occur, one of the c_i must be positive and one must
    // be negative.

    if ( iNegative == 0 )
    {
        // tetrahedron is completely on the positive side of plane, full clip
        return;
    }

    if ( iPositive == 0 )
    {
        // tetrahedron is completely on the negative side of plane
        rkInside.push_back(kTetra);
        return;
    }

    // Tetrahedron is split by plane.  Determine how it is split and how to
    // decompose the negative-side portion into tetrahedra (6 cases).
    Real fW0, fW1, fInvCDiff;
    Vector3 akIntp[4];

    if ( iPositive == 3 )
    {
        // +++-
        for (i = 0; i < iPositive; i++)
        {
            fInvCDiff = 1.0f/(afC[aiP[i]] - afC[aiN[0]]);
            fW0 = -afC[aiN[0]]*fInvCDiff;
            fW1 = +afC[aiP[i]]*fInvCDiff;
            kTetra[aiP[i]] = fW0*kTetra[aiP[i]] + fW1*kTetra[aiN[0]];
        }
        rkInside.push_back(kTetra);
    }
    else if ( iPositive == 2 )
    {
        if ( iNegative == 2 )
        {
            // ++--
            for (i = 0; i < iPositive; i++)
            {
                fInvCDiff = 1.0f/(afC[aiP[i]]-afC[aiN[0]]);
                fW0 = -afC[aiN[0]]*fInvCDiff;
                fW1 = +afC[aiP[i]]*fInvCDiff;
                akIntp[i] = fW0*kTetra[aiP[i]] + fW1*kTetra[aiN[0]];
            }
            for (i = 0; i < iNegative; i++)
            {
                fInvCDiff = 1.0f/(afC[aiP[i]]-afC[aiN[1]]);
                fW0 = -afC[aiN[1]]*fInvCDiff;
                fW1 = +afC[aiP[i]]*fInvCDiff;
                akIntp[i+2] = fW0*kTetra[aiP[i]] + fW1*kTetra[aiN[1]];
            }

            kTetra[aiP[0]] = akIntp[2];
            kTetra[aiP[1]] = akIntp[1];
            rkInside.push_back(kTetra);

            rkInside.push_back(Tetrahedron(kTetra[aiN[1]],akIntp[3],akIntp[2],
                akIntp[1]));

            rkInside.push_back(Tetrahedron(kTetra[aiN[0]],akIntp[0],akIntp[1],
                akIntp[2]));
        }
        else
        {
            // ++-0
            for (i = 0; i < iPositive; i++)
            {
                fInvCDiff = 1.0f/(afC[aiP[i]]-afC[aiN[0]]);
                fW0 = -afC[aiN[0]]*fInvCDiff;
                fW1 = +afC[aiP[i]]*fInvCDiff;
                kTetra[aiP[i]] = fW0*kTetra[aiP[i]] + fW1*kTetra[aiN[0]];
            }
            rkInside.push_back(kTetra);
        }
    }
    else if ( iPositive == 1 )
    {
        if ( iNegative == 3 )
        {
            // +---
            for (i = 0; i < iNegative; i++)
            {
                fInvCDiff = 1.0f/(afC[aiP[0]]-afC[aiN[i]]);
                fW0 = -afC[aiN[i]]*fInvCDiff;
                fW1 = +afC[aiP[0]]*fInvCDiff;
                akIntp[i] = fW0*kTetra[aiP[0]] + fW1*kTetra[aiN[i]];
            }

            kTetra[aiP[0]] = akIntp[0];
            rkInside.push_back(kTetra);

            rkInside.push_back(Tetrahedron(akIntp[0],kTetra[aiN[1]],
                kTetra[aiN[2]],akIntp[1]));

            rkInside.push_back(Tetrahedron(kTetra[aiN[2]],akIntp[1],akIntp[2],
                akIntp[0]));
        }
        else if ( iNegative == 2 )
        {
            // +--0
            for (i = 0; i < iNegative; i++)
            {
                fInvCDiff = 1.0f/(afC[aiP[0]]-afC[aiN[i]]);
                fW0 = -afC[aiN[i]]*fInvCDiff;
                fW1 = +afC[aiP[0]]*fInvCDiff;
                akIntp[i] = fW0*kTetra[aiP[0]] + fW1*kTetra[aiN[i]];
            }

            kTetra[aiP[0]] = akIntp[0];
            rkInside.push_back(kTetra);

            rkInside.push_back(Tetrahedron(akIntp[1],kTetra[aiZ[0]],
                kTetra[aiN[1]],akIntp[0]));
        }
        else
        {
            // +-00
            fInvCDiff = 1.0f/(afC[aiP[0]]-afC[aiN[0]]);
            fW0 = -afC[aiN[0]]*fInvCDiff;
            fW1 = +afC[aiP[0]]*fInvCDiff;
            kTetra[aiP[0]] = fW0*kTetra[aiP[0]] + fW1*kTetra[aiN[0]];
            rkInside.push_back(kTetra);
        }
    }
}
Example #5
0
//----------------------------------------------------------------------------
int ConvexClipper::Clip (const Plane& rkPlane)
{
    // compute signed distances from vertices to plane
    int iPositive = 0, iNegative = 0;
    for (int iV = 0; iV < (int)m_akVertex.size(); iV++)
    {
        Vertex& rkV = m_akVertex[iV];
        if ( rkV.m_bVisible )
        {
            rkV.m_fDistance = rkPlane.DistanceTo(rkV.m_kPoint);
            if ( rkV.m_fDistance >= m_fEpsilon )
            {
                iPositive++;
            }
            else if ( rkV.m_fDistance <= -m_fEpsilon )
            {
                iNegative++;
                rkV.m_bVisible = false;
            }
            else
            {
                // The point is on the plane (within floating point
                // tolerance).
                rkV.m_fDistance = 0.0f;
            }
        }
    }

    if ( iPositive == 0 )
    {
        // mesh is in negative half-space, fully clipped
        return Plane::NEGATIVE_SIDE;
    }

    if ( iNegative == 0 )
    {
        // mesh is in positive half-space, fully visible
        return Plane::POSITIVE_SIDE;
    }

    // clip the visible edges
    for (int iE = 0; iE < (int)m_akEdge.size(); iE++)
    {
        Edge& rkE = m_akEdge[iE];
        if ( rkE.m_bVisible )
        {
            int iV0 = rkE.m_aiVertex[0], iV1 = rkE.m_aiVertex[1];
            int iF0 = rkE.m_aiFace[0], iF1 = rkE.m_aiFace[1];
            Face& rkF0 = m_akFace[iF0];
            Face& rkF1 = m_akFace[iF1];
            Real fD0 = m_akVertex[iV0].m_fDistance;
            Real fD1 = m_akVertex[iV1].m_fDistance;

            if ( fD0 <= 0.0f && fD1 <= 0.0f )
            {
                // The edge is culled.  If the edge is exactly on the clip
                // plane, it is possible that a visible triangle shares it.
                // The edge will be re-added during the face loop.
                rkF0.m_akEdge.erase(iE);
                if ( rkF0.m_akEdge.empty() )
                    rkF0.m_bVisible = false;

                rkF1.m_akEdge.erase(iE);
                if ( rkF1.m_akEdge.empty() )
                    rkF1.m_bVisible = false;

                rkE.m_bVisible = false;
                continue;
            }

            if ( fD0 >= 0.0f && fD1 >= 0.0f )
            {
                // face retains the edge
                continue;
            }

            // The edge is split by the plane.  Compute the point of
            // intersection.  If the old edge is <V0,V1> and I is the
            // intersection point, the new edge is <V0,I> when d0 > 0 or
            // <I,V1> when d1 > 0.
            int iNV = m_akVertex.size();
            m_akVertex.push_back(Vertex());
            Vertex& rkNV = m_akVertex[iNV];

            Vector3& rkP0 = m_akVertex[iV0].m_kPoint;
            Vector3& rkP1 = m_akVertex[iV1].m_kPoint;
            rkNV.m_kPoint = rkP0+(fD0/(fD0-fD1))*(rkP1-rkP0);

            if ( fD0 > 0.0f )
                rkE.m_aiVertex[1] = iNV;
            else
                rkE.m_aiVertex[0] = iNV;
        }
    }

    // The mesh straddles the plane.  A new convex polygonal face will be
    // generated.  Add it now and insert edges when they are visited.
    int iNF = m_akFace.size();
    m_akFace.push_back(Face());
    Face& rkNF = m_akFace[iNF];
    rkNF.m_kPlane = rkPlane;

    // process the faces
    for (int iF = 0; iF < iNF; iF++)
    {
        Face& rkF = m_akFace[iF];
        if ( rkF.m_bVisible )
        {
            // Determine if the face is on the negative side, the positive
            // side, or split by the clipping plane.  The m_iOccurs members
            // are set to zero to help find the end points of the polyline
            // that results from clipping a face.
            assert( rkF.m_akEdge.size() >= 2 );
            set<int>::iterator pkIter = rkF.m_akEdge.begin();
            while ( pkIter != rkF.m_akEdge.end() )
            {
                int iE = *pkIter++;
                Edge& rkE = m_akEdge[iE];
                assert( rkE.m_bVisible );
                m_akVertex[rkE.m_aiVertex[0]].m_iOccurs = 0;
                m_akVertex[rkE.m_aiVertex[1]].m_iOccurs = 0;
            }

            int iVStart, iVFinal;
            if ( GetOpenPolyline(rkF,iVStart,iVFinal) )
            {
                // polyline is open, close it up
                int iNE = m_akEdge.size();
                m_akEdge.push_back(Edge());
                Edge& rkNE = m_akEdge[iNE];

                rkNE.m_aiVertex[0] = iVStart;
                rkNE.m_aiVertex[1] = iVFinal;
                rkNE.m_aiFace[0] = iF;
                rkNE.m_aiFace[1] = iNF;

                // add new edge to polygons
                rkF.m_akEdge.insert(iNE);
                rkNF.m_akEdge.insert(iNE);
            }
        }
    }

    // Process face rkNF to make sure it is a simple polygon (theoretically
    // convex, but numerically may be slightly not convex).  Floating point
    // round-off errors can cause the new face from the last loop to be
    // needle-like with a collapse of two edges into a single edge.  This
    // block guarantees the invariant "face always a simple polygon".
    PostProcess(iNF,rkNF);
    int iESize = rkNF.m_akEdge.size();
    if ( iESize < 3 )
    {
        // face is completely degenerate, remove it from mesh
        m_akFace.pop_back();
    }

    return Plane::NO_SIDE;
}