Exemplo n.º 1
0
        /// <summary>
        ///		Plane/Box intersection test.
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="box"></param>
        /// <returns>True if there was an intersection, false otherwise.</returns>
        public static bool Intersects(Plane plane, AxisAlignedBox box)
        {
            if (box.IsNull)
            {
                return(false);
            }

            // Get corners of the box
            Vector3[] corners = box.Corners;

            // Test which side of the plane the corners are
            // Intersection occurs when at least one corner is on the
            // opposite side to another
            PlaneSide lastSide = plane.GetSide(corners[0]);

            for (int corner = 1; corner < 8; corner++)
            {
                if (plane.GetSide(corners[corner]) != lastSide)
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        ///		Intersection test with an <see cref="AxisAlignedBox2"/>.
        /// </summary>
        /// <remarks>
        ///		May return false positives but will never miss an intersection.
        /// </remarks>
        /// <param name="box">Box to test.</param>
        /// <returns>True if interesecting, false otherwise.</returns>
        public bool Intersects(AxisAlignedBox3 box)
        {
            if (box.IsNull)
            {
                return(false);
            }

            if (box.IsInfinite)
            {
                return(true);
            }

            // Get centre of the box
            Vector3 center = box.Center;
            // Get the half-size of the box
            Vector3 halfSize = box.HalfSize;

            // If all points are on outside of any plane, we fail
            Vector3[] points = box.Corners;

            for (int i = 0; i < planes.Count; i++)
            {
                Plane plane = (Plane)planes[i];

                PlaneSide side = plane.GetSide(center, halfSize);
                if (side == outside)
                {
                    // Found a splitting plane therefore return not intersecting
                    return(false);
                }
            }

            // couldn't find a splitting plane, assume intersecting
            return(true);
        }
Exemplo n.º 3
0
        public bool IsObjectVisible(Sphere bound)
        {
            // Check originplane if told to
            if (this.mUseOriginPlane)
            {
                PlaneSide side = this.mOriginPlane.GetSide(bound.Center);
                if (side == PlaneSide.Negative)
                {
                    Real dist = this.mOriginPlane.GetDistance(bound.Center);
                    if (dist > bound.Radius)
                    {
                        return(false);
                    }
                }
            }

            // For each extra active culling plane, see if the entire sphere is on the negative side
            // If so, object is not visible
            foreach (PCPlane plane in this.mActiveCullingPlanes)
            {
                PlaneSide xside = plane.GetSide(bound.Center);
                if (xside == PlaneSide.Negative)
                {
                    float dist = this.mOriginPlane.GetDistance(bound.Center);
                    if (dist > bound.Radius)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Exemplo n.º 4
0
        /// <summary>
        ///     A 'more detailed' check for visibility of an AAB.
        /// </summary>
        /// <remarks>
        ///     This is useful for stuff like Octree leaf culling.
        /// </remarks>
        /// <param name="bound">the <see cref="AxisAlignedBox"/> to check visibility aginst.</param>
        /// <returns>
        ///     None, Partial, or Full for visibility of the box.
        /// </returns>
        public PCZFrustum.Visibility GetVisibility(AxisAlignedBox bound)
        {
            // Null boxes always invisible
            if (bound.IsNull)
            {
                return(PCZFrustum.Visibility.None);
            }

            // Get centre of the box
            Vector3 centre = bound.Center;
            // Get the half-size of the box
            Vector3 halfSize = bound.HalfSize;

            bool all_inside = true;

            for (int plane = 0; plane < 6; ++plane)
            {
                // Skip far plane if infinite view frustum
                if (plane == (int)FrustumPlane.Far && Far == 0)
                {
                    continue;
                }

                // This updates frustum planes and deals with cull frustum
                PlaneSide side = FrustumPlanes[plane].GetSide(centre, halfSize);
                if (side == PlaneSide.Negative)
                {
                    return(PCZFrustum.Visibility.None);
                }
                // We can't return now as the box could be later on the negative side of a plane.
                if (side == PlaneSide.Both)
                {
                    all_inside = false;
                }
            }

            switch (this.extraCullingFrustum.GetVisibility(bound))
            {
            case PCZFrustum.Visibility.None:
                return(PCZFrustum.Visibility.None);

            case PCZFrustum.Visibility.Partial:
                return(PCZFrustum.Visibility.Partial);

            case PCZFrustum.Visibility.Full:
                break;
            }

            if (all_inside)
            {
                return(PCZFrustum.Visibility.Full);
            }
            else
            {
                return(PCZFrustum.Visibility.Partial);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        ///     A 'more detailed' check for visibility of an AAB.
        /// </summary>
        /// <remarks>
        ///     This is useful for stuff like Octree leaf culling.
        /// </remarks>
        /// <param name="bound">the <see cref="AxisAlignedBox"/> to check visibility aginst.</param>
        /// <returns>
        ///     None, Partial, or Full for visibility of the box.
        /// </returns>
        public Visibility GetVisibility(AxisAlignedBox bound)
        {
            // Null boxes always invisible
            if (bound.IsNull)
            {
                return(Visibility.None);
            }

            // Get centre of the box
            Vector3 centre = bound.Center;
            // Get the half-size of the box
            Vector3 halfSize = bound.HalfSize;

            bool all_inside = true;

            // Check originplane if told to
            if (this.mUseOriginPlane)
            {
                PlaneSide side = this.mOriginPlane.GetSide(centre, halfSize);
                if (side == PlaneSide.Negative)
                {
                    return(Visibility.None);
                }
                // We can't return now as the box could be later on the negative side of another plane.
                if (side == PlaneSide.Both)
                {
                    all_inside = false;
                }
            }

            // For each active culling plane, see if the entire aabb is on the negative side
            // If so, object is not visible
            foreach (PCPlane plane in this.mActiveCullingPlanes)
            {
                PlaneSide xside = plane.GetSide(centre, halfSize);
                if (xside == PlaneSide.Negative)
                {
                    return(Visibility.None);
                }
                // We can't return now as the box could be later on the negative side of a plane.
                if (xside == PlaneSide.Both)
                {
                    all_inside = false;
                }
            }

            if (all_inside)
            {
                return(Visibility.Full);
            }
            else
            {
                return(Visibility.Partial);
            }
        }
Exemplo n.º 6
0
        static bool areAllVerteciesOnTheSameSide(PlaneSide aSide, PlaneSide bSide, PlaneSide cSide, PlaneSide side)
        {
            bool result = false;

            if (aSide == side &&
                bSide == side &&
                cSide == side)
            {
                result = true;
            }
            else if (aSide == PlaneSide.ON_PLANE &&
                     bSide == side &&
                     cSide == side)
            {
                result = true;
            }
            else if (bSide == PlaneSide.ON_PLANE &&
                     cSide == side &&
                     aSide == side)
            {
                result = true;
            }
            else if (cSide == PlaneSide.ON_PLANE &&
                     aSide == side &&
                     bSide == side)
            {
                result = true;
            }
            else if (aSide == PlaneSide.ON_PLANE &&
                     bSide == PlaneSide.ON_PLANE &&
                     cSide == side)
            {
                result = true;
            }
            else if (bSide == PlaneSide.ON_PLANE &&
                     cSide == PlaneSide.ON_PLANE &&
                     aSide == side)
            {
                result = true;
            }
            else if (cSide == PlaneSide.ON_PLANE &&
                     aSide == PlaneSide.ON_PLANE &&
                     bSide == side)
            {
                result = true;
            }

            return(result);
        }
Exemplo n.º 7
0
        /** Checks how the axis aligned box intersects with the plane bounded volume
         */

        private static Intersection intersect(PlaneBoundedVolume one, AxisAlignedBox two)
        {
            // Null box?
            if (two.IsNull)
            {
                return(Intersection.OUTSIDE);
            }
            // Infinite box?
            if (two.IsInfinite)
            {
                return(Intersection.INTERSECT);
            }

            // Get centre of the box
            Vector3 centre = two.Center;
            // Get the half-size of the box
            Vector3 halfSize = two.HalfSize;

            // For each plane, see if all points are on the negative side
            // If so, object is not visible.
            // If one or more are, it's partial.
            // If all aren't, full
            bool all_inside = true;


            foreach (Plane plane in one.planes)
            {
                PlaneSide side = plane.GetSide(centre, halfSize);
                if (side == one.outside)
                {
                    return(Intersection.OUTSIDE);
                }
                if (side == PlaneSide.Both)
                {
                    all_inside = false;
                }
            }

            if (all_inside)
            {
                return(Intersection.INSIDE);
            }
            else
            {
                return(Intersection.INTERSECT);
            }
        }
        /// <summary>
        ///		Gets the next node down in the tree, with the intention of locating the leaf containing the given point.
        /// </summary>
        /// <remarks>
        ///		This method should only be called on a splitting node, i.e. where <see cref="Plugin_BSPSceneManager.BspSceneNode"/> returns false.
        ///		Calling this method on a leaf node will throw an exception.
        /// </remarks>
        public BspNode GetNextNode(Vector3 point)
        {
            if (IsLeaf)
            {
                throw new Exception("This property is not valid on a leaf node.");
            }

            PlaneSide sd = GetSide(point);

            if (sd == PlaneSide.Negative)
            {
                return(this.BackNode);
            }
            else
            {
                return(this.FrontNode);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Return positive number if given point is on the same side of plane that
        /// plane normal is facing. Negative number otherwise.
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public PlaneSide GetSide(Vector3 point)
        {
            PlaneSide result = PlaneSide.INVALID;
            float     dot    = Vector3.Dot(Normal, Origin - point);

            if (dot == 0)
            {
                result = PlaneSide.ON_PLANE;
            }
            else if (dot > 0)
            {
                result = PlaneSide.POSITIVE;
            }
            else
            {
                result = PlaneSide.NEGATIVE;
            }

            return(result);
        }
Exemplo n.º 10
0
        /// <summary>
        ///     Returns the visiblity of the box.
        /// </summary>
        /// <param name="bound"></param>
        /// <returns></returns>
        public Visibility GetVisibility(AxisAlignedBox bound)
        {
            if (bound.IsNull)
            {
                return(Visibility.None);
            }
            var center   = bound.Center;
            var halfSize = bound.HalfSize;

            var allInside = true;

            for (int plane = 0; plane < 6; plane++)
            {
                // Skip far plane if infinite view frustum
                if (plane == (int)FrustumPlane.Far && Far == 0)
                {
                    continue;
                }

                // This updates frustum planes and deals with cull frustum
                PlaneSide side = this.FrustumPlanes[plane].GetSide(center, halfSize);
                if (side == PlaneSide.Negative)
                {
                    return(Visibility.None);
                }
                // We can't return now as the box could be later on the negative side of a plane.
                if (side == PlaneSide.Both)
                {
                    allInside = false;
                }
            }

            if (allInside)
            {
                return(Visibility.Full);
            }
            else
            {
                return(Visibility.Partial);
            }
        }
Exemplo n.º 11
0
        public bool IsObjectVisible(AxisAlignedBox bound)
        {
            // Null boxes are always invisible
            if (bound.IsNull)
            {
                return(false);
            }

            // Infinite boxes are always visible
            if (bound.IsInfinite)
            {
                return(true);
            }

            // Get centre of the box
            Vector3 centre = bound.Center;
            // Get the half-size of the box
            Vector3 halfSize = bound.HalfSize;

            // Check originplane if told to
            if (this.mUseOriginPlane)
            {
                PlaneSide side = this.mOriginPlane.GetSide(centre, halfSize);
                if (side == PlaneSide.Negative)
                {
                    return(false);
                }
            }

            // For each extra active culling plane, see if the entire aabb is on the negative side
            // If so, object is not visible
            foreach (PCPlane plane in this.mActiveCullingPlanes)
            {
                PlaneSide xside = plane.GetSide(centre, halfSize);
                if (xside == PlaneSide.Negative)
                {
                    return(false);
                }
            }
            return(true);
        }
Exemplo n.º 12
0
    /**
     * Compute the two new triangles when only one point is on the plane.
     * It avoids to duplicate code.
     */
    private void TriangleSliceWithOnePointOnPlane(Vector3 pA, Vector3 pB, Vector3 pC, Vector3 nA, Vector3 nB, Vector3 nC, Vector2 uvA, Vector2 uvB, Vector2 uvC, PlaneSide planeSideB)
    {
        float distance;

        if (_plane.Intersects(pB, pC, out distance))
        {
            // If the plane cuts at B-C we have to compute two new triangles : A-B-BC and A-BC-C
            Vector3 pBC  = Vector3.Lerp(pB, pC, distance);
            Vector3 nBC  = Vector3.Lerp(nB, nC, distance);
            Vector3 uvBC = Vector3.Lerp(uvB, uvC, distance);

            Triangle newTriangleB = new Triangle(pA, pB, pBC);
            newTriangleB.SetNormals(nA, nB, nBC);
            newTriangleB.SetUVs(uvA, uvB, uvBC);

            Triangle newTriangleC = new Triangle(pA, pBC, pC);
            newTriangleC.SetNormals(nA, nBC, nC);
            newTriangleC.SetUVs(uvA, uvBC, uvC);

            if (planeSideB == PlaneSide.UP)
            {
                _upperMesh.Add(newTriangleB);
                _lowerMesh.Add(newTriangleC);
            }
            else
            {
                _upperMesh.Add(newTriangleC);
                _lowerMesh.Add(newTriangleB);
            }

            _cut.Add(pBC);
        }
        else
        {
            // If there isn't any intersection then we can push the whole triangle into whether the upper or the lower mesh
            Triangle newTriangle = new Triangle(pA, pB, pC);
            newTriangle.SetNormals(nA, nB, nC);
            newTriangle.SetUVs(uvA, uvB, uvC);

            if (planeSideB == PlaneSide.UP)
            {
                _upperMesh.Add(newTriangle);
            }
            else
            {
                _lowerMesh.Add(newTriangle);
            }
        }
    }
 /// <summary>
 ///		Constructor.
 /// </summary>
 /// <param name="outside">Side of the plane to be considered 'outside'.</param>
 public PlaneBoundedVolume(PlaneSide outside)
 {
     this.outside = outside;
 }
Exemplo n.º 14
0
        /// <summary>
        ///     IsObjectVisible() function for portals.
        /// </summary>
        /// <remarks>
        ///     Everything needs to be updated spatially before this function is
        ///     called including portal corners, frustum planes, etc.
        /// </remarks>
        /// <param name="portal">
        ///     The <see cref="Portal"/> to check visibility against.
        /// </param>
        /// <param name="culledBy">
        ///     The <see cref="FrustumPlane"/> that the Portal is in.
        /// </param>
        /// <returns>
        ///     true if the Portal is visible.
        /// </returns>
        public bool IsObjectVisible(Portal portal, out FrustumPlane culledBy)
        {
            culledBy = FrustumPlane.None;

            // if portal isn't open, it's not visible
            if (!portal.IsOpen)
            {
                return(false);
            }

            // check the extra frustum first
            if (!this.extraCullingFrustum.IsObjectVisible(portal))
            {
                return(false);
            }

            // if portal is of type AABB or Sphere, then use simple bound check against planes
            if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_AABB)
            {
                var aabb = new AxisAlignedBox(portal.getDerivedCorner(0), portal.getDerivedCorner(1));
                return(base.IsObjectVisible(aabb, out culledBy));
            }
            else if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE)
            {
                return(base.IsObjectVisible(portal.getDerivedSphere(), out culledBy));
            }

            // check if the portal norm is facing the camera
            Vector3 cameraToPortal  = portal.getDerivedCP() - DerivedPosition;
            Vector3 portalDirection = portal.getDerivedDirection();
            Real    dotProduct      = cameraToPortal.Dot(portalDirection);

            if (dotProduct > 0)
            {
                // portal is faced away from camera
                return(false);
            }
            // check against regular frustum planes
            bool visible_flag;

            if (null != CullFrustum)
            {
                // For each frustum plane, see if all points are on the negative side
                // If so, object is not visible
                // NOTE: We skip the NEAR plane (plane #0) because Portals need to
                // be visible no matter how close you get to them.

                for (int plane = 1; plane < 6; ++plane)
                {
                    // set the visible flag to false
                    visible_flag = false;
                    // Skip far plane if infinite view frustum
                    if ((FrustumPlane)plane == FrustumPlane.Far && _farDistance == 0)
                    {
                        continue;
                    }

                    // we have to check each corner of the portal
                    for (int corner = 0; corner < 4; corner++)
                    {
                        PlaneSide side = CullFrustum.FrustumPlanes[plane].GetSide(portal.getDerivedCorner(corner));
                        if (side != PlaneSide.Negative)
                        {
                            visible_flag = true;
                        }
                    }
                    // if the visible_flag is still false, then this plane
                    // culled all the portal points
                    if (visible_flag == false)
                    {
                        // ALL corners on negative side therefore out of view
                        if (culledBy != FrustumPlane.None)
                        {
                            culledBy = (FrustumPlane)plane;
                        }
                        return(false);
                    }
                }
            }
            else
            {
                // Make any pending updates to the calculated frustum planes
                UpdateFrustumPlanes();

                // For each frustum plane, see if all points are on the negative side
                // If so, object is not visible
                // NOTE: We skip the NEAR plane (plane #0) because Portals need to
                // be visible no matter how close you get to them.
                // BUGBUG: This can cause a false positive situation when a portal is
                // behind the camera but close.  This could be fixed by having another
                // culling plane at the camera location with normal same as camera direction.
                for (int plane = 1; plane < 6; ++plane)
                {
                    // set the visible flag to false
                    visible_flag = false;
                    // Skip far plane if infinite view frustum
                    if ((FrustumPlane)plane == FrustumPlane.Far && _farDistance == 0)
                    {
                        continue;
                    }

                    // we have to check each corner of the portal
                    for (int corner = 0; corner < 4; corner++)
                    {
                        PlaneSide side = _planes[plane].GetSide(portal.getDerivedCorner(corner));
                        if (side != PlaneSide.Negative)
                        {
                            visible_flag = true;
                        }
                    }
                    // if the visible_flag is still false, then this plane
                    // culled all the portal points
                    if (visible_flag == false)
                    {
                        // ALL corners on negative side therefore out of view
                        if (culledBy != FrustumPlane.None)
                        {
                            culledBy = (FrustumPlane)plane;
                        }
                        return(false);
                    }
                }
            }
            // no plane culled all the portal points and the norm
            // was facing the camera, so this portal is visible
            return(true);
        }
Exemplo n.º 15
0
        /// <summary>
        /// Split faces so that no face is intercepted by a face of other object
        /// </summary>
        /// <param name="compareObject">the other object 3d used to make the split</param>
        public void SplitFaces(CsgObject3D compareObject, CancellationToken cancellationToken,
                               Action <CsgFace, CsgFace> splitFaces = null,
                               Action <List <CsgFace> > results     = null)
        {
            Stack <CsgFace> newFacesFromSplitting = new Stack <CsgFace>();

            int numFacesStart = this.Faces.Count;

            //if the objects bounds overlap...
            //for each object1 face...
            var bounds = compareObject.GetBound();

            Faces.SearchBounds(bounds);
            foreach (var thisFaceIn in Faces.QueryResults)             // put it in an array as we will be adding new faces to it
            {
                newFacesFromSplitting.Push(thisFaceIn);
                // make sure we process every face that we have added during splitting before moving on to the next face
                while (newFacesFromSplitting.Count > 0)
                {
                    var faceToSplit = newFacesFromSplitting.Pop();

                    // stop processing if operation has been canceled
                    cancellationToken.ThrowIfCancellationRequested();

                    //if object1 face bound and object2 bound overlap ...
                    //for each object2 face...
                    compareObject.Faces.SearchBounds(faceToSplit.GetBound());
                    foreach (var cuttingFace in compareObject.Faces.QueryResults)
                    {
                        //if object1 face bound and object2 face bound overlap...
                        //PART I - DO TWO POLIGONS INTERSECT?
                        //POSSIBLE RESULTS: INTERSECT, NOT_INTERSECT, COPLANAR

                        //distance from the face1 vertices to the face2 plane
                        double v1DistToCuttingFace = cuttingFace.DistanceFromPlane(faceToSplit.v1);
                        double v2DistToCuttingFace = cuttingFace.DistanceFromPlane(faceToSplit.v2);
                        double v3DistToCuttingFace = cuttingFace.DistanceFromPlane(faceToSplit.v3);

                        //distances signs from the face1 vertices to the face2 plane
                        PlaneSide sideFace1Vert1 = (v1DistToCuttingFace > EqualityTolerance ? PlaneSide.Front : (v1DistToCuttingFace < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                        PlaneSide sideFace1Vert2 = (v2DistToCuttingFace > EqualityTolerance ? PlaneSide.Front : (v2DistToCuttingFace < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                        PlaneSide sideFace1Vert3 = (v3DistToCuttingFace > EqualityTolerance ? PlaneSide.Front : (v3DistToCuttingFace < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));

                        //if all the signs are zero, the planes are coplanar
                        //if all the signs are positive or negative, the planes do not intersect
                        //if the signs are not equal...
                        if (!(sideFace1Vert1 == sideFace1Vert2 && sideFace1Vert2 == sideFace1Vert3))
                        {
                            //distance from the face2 vertices to the face1 plane
                            double faceToSplitTo1 = faceToSplit.DistanceFromPlane(cuttingFace.v1);
                            double faceToSplitTo2 = faceToSplit.DistanceFromPlane(cuttingFace.v2);
                            double faceToSplitTo3 = faceToSplit.DistanceFromPlane(cuttingFace.v3);

                            //distances signs from the face2 vertices to the face1 plane
                            PlaneSide signFace2Vert1 = (faceToSplitTo1 > EqualityTolerance ? PlaneSide.Front : (faceToSplitTo1 < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                            PlaneSide signFace2Vert2 = (faceToSplitTo2 > EqualityTolerance ? PlaneSide.Front : (faceToSplitTo2 < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                            PlaneSide signFace2Vert3 = (faceToSplitTo3 > EqualityTolerance ? PlaneSide.Front : (faceToSplitTo3 < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));

                            //if the signs are not equal...
                            if (!(signFace2Vert1 == signFace2Vert2 && signFace2Vert2 == signFace2Vert3))
                            {
                                var line = new Line(faceToSplit, cuttingFace);

                                //intersection of the face1 and the plane of face2
                                var segment1 = new Segment(line, faceToSplit, sideFace1Vert1, sideFace1Vert2, sideFace1Vert3);

                                //intersection of the face2 and the plane of face1
                                var segment2 = new Segment(line, cuttingFace, signFace2Vert1, signFace2Vert2, signFace2Vert3);

                                //if the two segments intersect...
                                if (segment1.Intersect(segment2))
                                {
                                    //PART II - SUBDIVIDING NON-COPLANAR POLYGONS
                                    Stack <CsgFace> facesFromSplit = new Stack <CsgFace>();

                                    if (this.SplitFace(faceToSplit, segment1, segment2, facesFromSplit) &&
                                        facesFromSplit.Count > 0 &&
                                        !(facesFromSplit.Count == 1 && facesFromSplit.Peek().Equals(faceToSplit)))
                                    {
                                        foreach (var face in facesFromSplit)
                                        {
                                            newFacesFromSplitting.Push(face);
                                        }

                                        // send debugging information if registered
                                        splitFaces?.Invoke(faceToSplit, cuttingFace);
                                        results?.Invoke(facesFromSplit.ToList());

                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
 /// <summary>
 ///		Constructor.
 /// </summary>
 /// <param name="outside">Side of the plane to be considered 'outside'.</param>
 public PlaneBoundedVolume(PlaneSide outside)
 {
     this.outside = outside;
 }
Exemplo n.º 17
0
        /// <summary>
        /// Constructs a Segment based on elements obtained from the two planes relations
        /// </summary>
        /// <param name="line"></param>
        /// <param name="face"></param>
        /// <param name="side1"></param>
        /// <param name="side2"></param>
        /// <param name="side3"></param>
        public Segment(Line line, CsgFace face, PlaneSide side1, PlaneSide side2, PlaneSide side3)
        {
            this.line = line;
            index     = 0;

            //VERTEX is an end
            if (side1 == PlaneSide.On)
            {
                SetVertex(face.v1);
                //other vertices on the same side - VERTEX-VERTEX VERTEX
                if (side2 == side3)
                {
                    SetVertex(face.v1);
                }
            }

            //VERTEX is an end
            if (side2 == PlaneSide.On)
            {
                SetVertex(face.v2);
                //other vertices on the same side - VERTEX-VERTEX VERTEX
                if (side1 == side3)
                {
                    SetVertex(face.v2);
                }
            }

            //VERTEX is an end
            if (side3 == PlaneSide.On)
            {
                SetVertex(face.v3);
                //other vertices on the same side - VERTEX-VERTEX VERTEX
                if (side1 == side2)
                {
                    SetVertex(face.v3);
                }
            }

            //There are undefined ends - one or more edges cut the planes intersection line
            if (GetNumEndsSet() != 2)
            {
                //EDGE is an end
                if ((side1 == PlaneSide.Front && side2 == PlaneSide.Back) ||
                    (side1 == PlaneSide.Back && side2 == PlaneSide.Front))
                {
                    SetEdge(face.v1, face.v2);
                }
                //EDGE is an end
                if ((side2 == PlaneSide.Front && side3 == PlaneSide.Back) ||
                    (side2 == PlaneSide.Back && side3 == PlaneSide.Front))
                {
                    SetEdge(face.v2, face.v3);
                }
                //EDGE is an end
                if ((side3 == PlaneSide.Front && side1 == PlaneSide.Back) ||
                    (side3 == PlaneSide.Back && side1 == PlaneSide.Front))
                {
                    SetEdge(face.v3, face.v1);
                }
            }
        }
Exemplo n.º 18
0
    /**
     * Compute the three new triangles when the plane intersects with the triangle on two points.
     * Here the intersection points are AB and CA.
     * It avoids to duplicate code.
     */
    private void TriangleSliceWithTwoIntersections(Vector3 pA, Vector3 pB, Vector3 pC, Vector3 nA, Vector3 nB, Vector3 nC, Vector2 uvA, Vector2 uvB, Vector2 uvC, float coeffAB, float coeffCA, PlaneSide planeSideA)
    {
        Vector3 pAB  = Vector3.Lerp(pA, pB, coeffAB);
        Vector3 pCA  = Vector3.Lerp(pC, pA, coeffCA);
        Vector3 nAB  = Vector3.Lerp(nA, nB, coeffAB);
        Vector3 nCA  = Vector3.Lerp(nC, nA, coeffCA);
        Vector2 uvAB = Vector2.Lerp(uvA, uvB, coeffAB);
        Vector2 uvCA = Vector2.Lerp(uvC, uvA, coeffCA);

        Triangle triangle_A_AB_CA = new Triangle(pA, pAB, pCA);

        triangle_A_AB_CA.SetNormals(nA, nAB, nCA);
        triangle_A_AB_CA.SetUVs(uvA, uvAB, uvCA);

        Triangle triangle_B_CA_AB = new Triangle(pB, pCA, pAB);

        triangle_B_CA_AB.SetNormals(nB, nCA, nAB);
        triangle_B_CA_AB.SetUVs(uvB, uvCA, uvAB);

        Triangle triangle_C_CA_B = new Triangle(pC, pCA, pB);

        triangle_C_CA_B.SetNormals(nC, nCA, nB);
        triangle_C_CA_B.SetUVs(uvC, uvCA, uvB);

        if (planeSideA == PlaneSide.UP)
        {
            _upperMesh.Add(triangle_A_AB_CA);
            _lowerMesh.Add(triangle_B_CA_AB);
            _lowerMesh.Add(triangle_C_CA_B);
        }
        else
        {
            _upperMesh.Add(triangle_B_CA_AB);
            _upperMesh.Add(triangle_C_CA_B);
            _lowerMesh.Add(triangle_A_AB_CA);
        }
    }
Exemplo n.º 19
0
        /// <summary>
        ///     IsObjectVisible() function for portals.
        /// </summary>
        /// <remarks>
        ///     Everything needs to be updated spatially before this function is
        ///     called including portal corners, frustum planes, etc.
        /// </remarks>
        /// <param name="portal">
        ///     The <see cref="Portal"/> to check visibility against.
        /// </param>
        /// <returns>
        ///     true if the Portal is visible.
        /// </returns>
        public bool IsObjectVisible(Portal portal)
        {
            // if portal isn't open, it's not visible
            if (!portal.IsOpen)
            {
                return(false);
            }

            // if the frustum has no planes, just return true
            if (this.mActiveCullingPlanes.Count == 0)
            {
                return(true);
            }
            // check if this portal is already in the list of active culling planes (avoid
            // infinite recursion case)
            foreach (PCPlane plane in this.mActiveCullingPlanes)
            {
                if (plane.Portal == portal)
                {
                    return(false);
                }
            }

            // if portal is of type AABB or Sphere, then use simple bound check against planes
            if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_AABB)
            {
                var aabb = new AxisAlignedBox();
                aabb.SetExtents(portal.getDerivedCorner(0), portal.getDerivedCorner(1));
                return(IsObjectVisible(aabb));
            }
            else if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE)
            {
                return(IsObjectVisible(portal.getDerivedSphere()));
            }

            // check if the portal norm is facing the frustum
            Vector3 frustumToPortal = portal.getDerivedCP() - this.mOrigin;
            Vector3 portalDirection = portal.getDerivedDirection();
            Real    dotProduct      = frustumToPortal.Dot(portalDirection);

            if (dotProduct > 0)
            {
                // portal is faced away from Frustum
                return(false);
            }

            // check against frustum culling planes
            bool visible_flag;

            // Check originPlane if told to
            if (this.mUseOriginPlane)
            {
                // set the visible flag to false
                visible_flag = false;
                // we have to check each corner of the portal
                for (int corner = 0; corner < 4; corner++)
                {
                    PlaneSide side = this.mOriginPlane.GetSide(portal.getDerivedCorner(corner));
                    if (side != PlaneSide.Negative)
                    {
                        visible_flag = true;
                    }
                }
                // if the visible_flag is still false, then the origin plane
                // culled all the portal points
                if (visible_flag == false)
                {
                    // ALL corners on negative side therefore out of view
                    return(false);
                }
            }

            // For each active culling plane, see if all portal points are on the negative
            // side. If so, the portal is not visible
            foreach (PCPlane plane in this.mActiveCullingPlanes)
            {
                visible_flag = false;
                // we have to check each corner of the portal
                for (int corner = 0; corner < 4; corner++)
                {
                    PlaneSide side = plane.GetSide(portal.getDerivedCorner(corner));
                    if (side != PlaneSide.Negative)
                    {
                        visible_flag = true;
                    }
                }
                // if the visible_flag is still false, then this plane
                // culled all the portal points
                if (visible_flag == false)
                {
                    // ALL corners on negative side therefore out of view
                    return(false);
                }
            }

            // no plane culled all the portal points and the norm
            // was facing the frustum, so this portal is visible
            return(true);
        }
Exemplo n.º 20
0
        public static CutResult Cut(int [] meshTriangles, Vector3 [] meshVertives, Vector3 [] meshNormals, Vector2 [] meshUVs, Plane plane)
        {
            MeshData       aMeshData          = new MeshData();
            MeshData       bMeshData          = new MeshData();
            List <Vector3> sliceEdgeVertecies = new List <Vector3> ();

            for (int i = 0; i < meshTriangles.Length; i += 3)
            {
                int aVertexIndex = meshTriangles [i];
                int bVertexIndex = meshTriangles [i + 1];
                int cVertexIndex = meshTriangles [i + 2];

                PlaneSide aSide = plane.GetSide(meshVertives [aVertexIndex]);
                PlaneSide bSide = plane.GetSide(meshVertives [bVertexIndex]);
                PlaneSide cSide = plane.GetSide(meshVertives [cVertexIndex]);

                if (areAllVerteciesOnTheSameSide(aSide, bSide, cSide, PlaneSide.POSITIVE))
                {
                    bool addUV = meshUVs.Length > 0;

                    aMeshData.Add(meshVertives [aVertexIndex], meshNormals [aVertexIndex], addUV ? meshUVs [aVertexIndex] : Vector2.zero);
                    aMeshData.Add(meshVertives [bVertexIndex], meshNormals [bVertexIndex], addUV ? meshUVs [bVertexIndex] : Vector2.zero);
                    aMeshData.Add(meshVertives [cVertexIndex], meshNormals [cVertexIndex], addUV ? meshUVs [cVertexIndex] : Vector2.zero);

                    if (aSide == PlaneSide.ON_PLANE)
                    {
                        sliceEdgeVertecies.Add(meshVertives [aVertexIndex]);
                    }

                    if (bSide == PlaneSide.ON_PLANE)
                    {
                        sliceEdgeVertecies.Add(meshVertives [bVertexIndex]);
                    }

                    if (cSide == PlaneSide.ON_PLANE)
                    {
                        sliceEdgeVertecies.Add(meshVertives [cVertexIndex]);
                    }
                }
                else if (areAllVerteciesOnTheSameSide(aSide, bSide, cSide, PlaneSide.NEGATIVE))
                {
                    bool addUV = meshUVs.Length > 0;

                    bMeshData.Add(meshVertives [aVertexIndex], meshNormals [aVertexIndex], addUV ? meshUVs [aVertexIndex] : Vector2.zero);
                    bMeshData.Add(meshVertives [bVertexIndex], meshNormals [bVertexIndex], addUV ? meshUVs [bVertexIndex] : Vector2.zero);
                    bMeshData.Add(meshVertives [cVertexIndex], meshNormals [cVertexIndex], addUV ? meshUVs [cVertexIndex] : Vector2.zero);

                    if (aSide == PlaneSide.ON_PLANE)
                    {
                        sliceEdgeVertecies.Add(meshVertives [aVertexIndex]);
                    }

                    if (bSide == PlaneSide.ON_PLANE)
                    {
                        sliceEdgeVertecies.Add(meshVertives [bVertexIndex]);
                    }

                    if (cSide == PlaneSide.ON_PLANE)
                    {
                        sliceEdgeVertecies.Add(meshVertives [cVertexIndex]);
                    }
                }
                else if (aSide == PlaneSide.POSITIVE && bSide == PlaneSide.NEGATIVE && cSide == PlaneSide.NEGATIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPositiveHalfSpace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs,
                                                                     plane, aVertexIndex, bVertexIndex, cVertexIndex, sliceEdgeVertecies);
                }
                else if (bSide == PlaneSide.POSITIVE && cSide == PlaneSide.NEGATIVE && aSide == PlaneSide.NEGATIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPositiveHalfSpace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs,
                                                                     plane, bVertexIndex, cVertexIndex, aVertexIndex, sliceEdgeVertecies);
                }
                else if (cSide == PlaneSide.POSITIVE && aSide == PlaneSide.NEGATIVE && bSide == PlaneSide.NEGATIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPositiveHalfSpace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs,
                                                                     plane, cVertexIndex, aVertexIndex, bVertexIndex, sliceEdgeVertecies);
                }
                else if (aSide == PlaneSide.NEGATIVE && bSide == PlaneSide.POSITIVE && cSide == PlaneSide.POSITIVE)
                {
                    sliceTriangleWhenTwoVerticesAreOnAPositiveHalfSpace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane, bVertexIndex,
                                                                        cVertexIndex, aVertexIndex, sliceEdgeVertecies);
                }
                else if (bSide == PlaneSide.NEGATIVE && cSide == PlaneSide.POSITIVE && aSide == PlaneSide.POSITIVE)
                {
                    sliceTriangleWhenTwoVerticesAreOnAPositiveHalfSpace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane, cVertexIndex,
                                                                        aVertexIndex, bVertexIndex, sliceEdgeVertecies);
                }
                else if (cSide == PlaneSide.NEGATIVE && aSide == PlaneSide.POSITIVE && bSide == PlaneSide.POSITIVE)
                {
                    sliceTriangleWhenTwoVerticesAreOnAPositiveHalfSpace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane, aVertexIndex,
                                                                        bVertexIndex, cVertexIndex, sliceEdgeVertecies);
                }
                else if (aSide == PlaneSide.ON_PLANE && bSide == PlaneSide.POSITIVE && cSide == PlaneSide.NEGATIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPlaneAndNextIsOnAPositiveHalfspace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane, aVertexIndex, bVertexIndex,
                                                                                      cVertexIndex, sliceEdgeVertecies);
                }
                else if (aSide == PlaneSide.ON_PLANE)
                {
                    sliceTriangleWhenOneVertexIsOnAPlaneAndNextIsOnANegativeHalfspace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane, aVertexIndex,
                                                                                      bVertexIndex, cVertexIndex, sliceEdgeVertecies);
                }
                else if (bSide == PlaneSide.ON_PLANE && cSide == PlaneSide.POSITIVE && aSide == PlaneSide.NEGATIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPlaneAndNextIsOnAPositiveHalfspace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane,
                                                                                      bVertexIndex, cVertexIndex, aVertexIndex, sliceEdgeVertecies);
                }
                else if (bSide == PlaneSide.ON_PLANE && cSide == PlaneSide.NEGATIVE && aSide == PlaneSide.POSITIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPlaneAndNextIsOnANegativeHalfspace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane, bVertexIndex,
                                                                                      cVertexIndex, aVertexIndex, sliceEdgeVertecies);
                }
                else if (cSide == PlaneSide.ON_PLANE && aSide == PlaneSide.POSITIVE && bSide == PlaneSide.NEGATIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPlaneAndNextIsOnAPositiveHalfspace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane,
                                                                                      cVertexIndex, aVertexIndex, bVertexIndex, sliceEdgeVertecies);
                }
                else if (cSide == PlaneSide.ON_PLANE && aSide == PlaneSide.NEGATIVE && bSide == PlaneSide.POSITIVE)
                {
                    sliceTriangleWhenOneVertexIsOnAPlaneAndNextIsOnANegativeHalfspace(aMeshData, bMeshData, meshVertives, meshNormals, meshUVs, plane, cVertexIndex,
                                                                                      aVertexIndex, bVertexIndex, sliceEdgeVertecies);
                }
            }

            return(new CutResult(aMeshData, bMeshData, sliceEdgeVertecies, plane));
        }
Exemplo n.º 21
0
    //-----------------------------------------------------------------------
    public static bool Intersects(Ray ray, List <Plane> planeList, bool normalIsOutside, out float distance)
    {
        distance = float.NegativeInfinity;

        bool allInside = true;

        bool  ret     = false;
        float retDist = 0.0f;
        bool  end     = false;
        float endDist = 0.0f;

        // derive side
        // NB we don't pass directly since that would require Plane::Side in
        // interface, which results in recursive includes since Math is so fundamental
        PlaneSide outside = normalIsOutside ? PlaneSide.POSITIVE_SIDE : PlaneSide.NEGATIVE_SIDE;

        foreach (Plane plane in planeList)
        {
            // is origin outside?
            if (GetSide(plane, ray.origin) == outside)
            {
                allInside = false;
                // Test single plane
                if (Intersects(ray, plane, out distance))
                {
                    // Ok, we intersected
                    ret = true;
                    // Use the most distant result since convex volume
                    retDist = Mathf.Max(retDist, distance);
                }
                else
                {
                    distance = 0.0f;
                    return(false);
                }
            }
            else
            {
                if (Intersects(ray, plane, out distance))
                {
                    if (!end)
                    {
                        end     = true;
                        endDist = distance;
                    }
                    else
                    {
                        endDist = Mathf.Min(distance, endDist);
                    }
                }
            }
        }

        if (allInside)
        {
            // Intersecting at 0 distance since inside the volume!
            ret     = true;
            retDist = 0.0f;

            distance = retDist;
            return(ret);
        }

        if (end)
        {
            if (endDist < retDist)
            {
                ret      = false;
                distance = float.NegativeInfinity;
                return(ret);
            }
        }

        return(ret);
    }