Exemple #1
0
    // Split this Face with given Plane
    public bool Split(Plane inPlane, out CSGFace outFront, out CSGFace outBack)
    {
        outFront = new CSGFace();
        outBack  = new CSGFace();

        float[]      distance = new float[vertices.Length + 1];
        EPlaneSide[] side     = new EPlaneSide[vertices.Length + 1];


        for (int i = 0; i < vertices.Length; ++i)
        {
            distance[i] = inPlane.GetDistanceToPoint(vertices[i]);
            side[i]     = Side(inPlane, vertices[i]);
        }

        distance[vertices.Length] = distance[0];
        side[vertices.Length]     = side[0];

        for (int i = 0; i < vertices.Length; ++i)
        {
            // if we lie on plane, add them to both
            if (side[i] == EPlaneSide.Side_Planar)
            {
                outFront.AddVertex(vertices[i], uv[i]);
                outBack.AddVertex(vertices[i], uv[i]);
                // nothing todo with this vertex
                continue;
            }

            // if we are on the front, add it to front face
            if (side[i] == EPlaneSide.Side_Front)
            {
                outFront.AddVertex(vertices[i], uv[i]);
            }
            // if we are on the back, add it to the back side
            else if (side[i] == EPlaneSide.Side_Back)
            {
                outBack.AddVertex(vertices[i], uv[i]);
            }

            // check if the next vertex is planar or on the same side, then we do not split
            if (side[i + 1] == EPlaneSide.Side_Planar || side[i] == side[i + 1])
            {
                continue;
            }

            // create split point
            Vector3 nextVector = vertices[(i + 1) % vertices.Length];
            Vector2 nextUV = uv[(i + 1) % uv.Length];
            Vector3 newVector, newUV;

            // if we were on the front
            if (side[i] == EPlaneSide.Side_Front)
            {
                float t = distance[i] / (distance[i] - distance[i + 1]);

                newVector = vertices[i] + t * (nextVector - vertices[i]);
                newUV     = uv[i] + t * (nextUV - uv[i]);
            }
            else             // back side...
            {
                float t = distance[i + 1] / (distance[i + 1] - distance[i]);

                newVector = nextVector + t * (vertices[i] - nextVector);
                newUV     = nextUV + t * (uv[i] - nextUV);
            }

            // split points are added

            // add to front
            outFront.AddVertex(newVector, newUV);

            // add to back
            outBack.AddVertex(newVector, newUV);
        }

        // Debugging checks
        if (outFront.vertices.Length < 3 || outBack.vertices.Length < 3)
        {
            Debug.Log("Degenerate Faces");
        }


        // todo...
        outFront.material = material;

        //
        outBack.material = material;

        return(true);
    }
Exemple #2
0
    /// <summary>
    /// Splits the face in a back and front part.
    /// </summary>
    /// <param name="face"></param>
    /// <param name="splittingPlane"></param>
    /// <returns></returns>
    private EPlaneSide splitFaceByPlane(
        Face face
        , Plane splittingPlane
        , out Face frontFace_, out Face backFace_
        , float epsilon = 1e-3f//CLIP_EPSILON
        )
    {
        var numVertices = face.vertices.Count;

        var dists = new float[numVertices + 1];
        var sides = new EPlaneSide[numVertices + 1];

        // First, classify all points. This allows us to avoid any bisection if possible
        var counts     = new int[3]; // 'on', 'back' and 'front'
        var faceStatus = (int)EPlaneSide.On;

        // determine sides for each point
        for (int i = 0; i < numVertices; i++)
        {
            var vertex = face.vertices[i];
            var d      = splittingPlane.GetDistanceToPoint(vertex);
            dists[i] = d;
            var side = (d > +epsilon)
                                    ? EPlaneSide.Front
                                    : (d < -epsilon) ? EPlaneSide.Back : EPlaneSide.On;
            sides[i]    = side;
            faceStatus |= (int)side;
            counts[(int)side]++;
        }
        sides[numVertices] = sides[0];
        dists[numVertices] = dists[0];

        //
        if (faceStatus != (int)EPlaneSide.Split)
        {
            backFace_  = face;
            frontFace_ = face;
            return((EPlaneSide)faceStatus);
        }
        Debug.DebugBreak();//AAA
        // Straddles the splitting plane - we must clip.

        //mxBIBREF("'float-Time Collision Detection' by Christer Ericson (2005), 8.3.4 Splitting Polygons Against a Plane, PP.369-373");

        var MAX_VERTS = 32;

        var backVerts  = new Vector3[MAX_VERTS];
        var frontVerts = new Vector3[MAX_VERTS];

        var numFront = 0;
        var numBack  = 0;


        // Test all edges (a, b) starting with edge from last to first Vector3
        Vector3    vA    = face.vertices[numVertices - 1];
        float      distA = dists[numVertices - 1];
        EPlaneSide sideA = sides[numVertices - 1];

        // Loop over all edges given by Vector3 pair (n - 1, n)
        for (int i = 0; i < numVertices; i++)
        {
            Vector3    vB    = face.vertices[i];
            float      distB = dists[i];
            EPlaneSide sideB = sides[i];
            if (sideB == EPlaneSide.Front)
            {
                if (sideA == EPlaneSide.Back)
                {
                    // Edge (a, b) straddles, output intersection point to both sides
                    // always calculate the split going from the same side or minor epsilon issues can happen
                    Vector3 v = getIntersectionPoint(vB, vA, distB, distA);
                    Debug.Assert(classifyPoint(v, splittingPlane, epsilon) == EPlaneSide.On);
                    frontVerts[numFront++] = backVerts[numBack++] = v;
                }
                // In all three cases, output b to the front side
                frontVerts[numFront++] = vB;
            }
            else if (sideB == EPlaneSide.Back)
            {
                if (sideA == EPlaneSide.Front)
                {
                    // Edge (a, b) straddles plane, output intersection point
                    Vector3 v = getIntersectionPoint(vA, vB, distA, distB);
                    Debug.Assert(classifyPoint(v, splittingPlane, epsilon) == EPlaneSide.On);
                    frontVerts[numFront++] = backVerts[numBack++] = v;
                }
                else if (sideA == EPlaneSide.On)
                {
                    // Output a when edge (a, b) goes from ‘on’ to ‘behind’ plane
                    backVerts[numBack++] = vA;
                }
                // In all three cases, output b to the back side
                backVerts[numBack++] = vB;
            }
            else
            {
                // b is on the plane. In all three cases output b to the front side
                frontVerts[numFront++] = vB;
                // In one case, also output b to back side
                if (sideA == EPlaneSide.Back)
                {
                    backVerts[numBack++] = vB;
                }
            }
            // Keep b as the starting point of the next edge
            vA    = vB;
            distA = distB;
            sideA = sideB;
        }

        //
        frontFace_          = new Face();
        frontFace_.vertices = frontVerts.ToList();

        backFace_          = new Face();
        backFace_.vertices = backVerts.ToList();

        Debug.Assert(faceStatus == (int)EPlaneSide.Split);
        return(EPlaneSide.Split);
    }
Exemple #3
0
	// Split this Face with given Plane
	public bool Split( Plane inPlane, out Face outFront, out Face outBack )
	{
		outFront = new Face();
		outBack = new Face();
		
		float[] distance = new float[vertices.Length + 1];
		EPlaneSide[] side = new EPlaneSide[vertices.Length + 1];
		
		
		for( int i = 0; i < vertices.Length; ++i )
		{
			distance[i] = inPlane.GetDistanceToPoint( vertices[i] );
			side[i] = Side( inPlane, vertices[i] );		
		}
		
		distance[vertices.Length] = distance[0];
		side[vertices.Length] = side[0];
		
		for( int i = 0; i < vertices.Length; ++i )
		{
			// if we lie on plane, add them to both
			if( side[i] == EPlaneSide.Side_Planar )
			{
				outFront.AddVertex( vertices[i], uv[i] );
				outBack.AddVertex( vertices[i], uv[i] );
				// nothing todo with this vertex
				continue;
			}
			
			// if we are on the front, add it to front face
			if( side[i] == EPlaneSide.Side_Front )
			{
				outFront.AddVertex( vertices[i], uv[i] );	
			}
			// if we are on the back, add it to the back side
			else if( side[i] == EPlaneSide.Side_Back )
			{
				outBack.AddVertex( vertices[i], uv[i] );
			}
			
			// check if the next vertex is planar or on the same side, then we do not split
			if( side[i+1] == EPlaneSide.Side_Planar || side[i] == side[i+1] )
				continue;
			
			// create split point
			Vector3 nextVector = vertices[ (i+1) % vertices.Length];
			Vector2 nextUV = uv[ (i+1) % uv.Length];
			Vector3 newVector, newUV;
			
			// if we were on the front
			if( side[i] == EPlaneSide.Side_Front )
			{
				float t = distance[i] / (distance[i] - distance[i+1]);
				
				newVector = vertices[i] + t * (nextVector - vertices[i]);
				newUV = uv[i] + t * (nextUV - uv[i]);
			}
			else // back side...
			{
				float t = distance[i+1] / (distance[i+1] - distance[i]);
				
				newVector = nextVector + t * (vertices[i] - nextVector);
				newUV = nextUV + t * (uv[i] - nextUV);
			}
			
			// split points are added
			
			// add to front
			outFront.AddVertex( newVector, newUV );
			
			// add to back
			outBack.AddVertex( newVector, newUV );
		}
	
		// Debugging checks
		if( outFront.vertices.Length < 3 || outBack.vertices.Length < 3 )
			Debug.Log("Degenerate Faces");
		
		
		// todo...
		outFront.material = material;
		
		// 
		outBack.material = material;
		
		return true;
	}