コード例 #1
0
        static private List <Triangle> FindTrianglesInsidePlanes(List <Triangle> tris, List <Plane> planes)
        {
            // TODO: a triangle can be 'inside' all planes (each plane has at least one triangle vertex 'inside' the plane),
            // yet the triangle can still not intersect the volume defined by the planes.
            // Do we need to clip the triangle to each plane to figure out if any part of the triangle lies 'inside' all planes?

            var newTris = new List <Raytrace.Triangle>();

            foreach (var tri in tris)
            {
                bool triInside = true;
                foreach (var plane in planes)
                {
                    PlaneHalfSpace side = tri.IntersectPlane(plane);
                    if ((side & PlaneHalfSpace.NormalSide) == 0)
                    {
                        triInside = false;
                        break;
                    }
                }

                if (triInside)
                {
                    newTris.Add(tri);
                }
            }
            return(newTris);
        }
コード例 #2
0
        /// <summary>
        /// Intersect a plane against this object.
        /// </summary>
        /// <param name="plane">The plane to test for intersection against.</param>
        /// <returns>The plane half-spaces intersected by the object, as a bitwise enumeration.
        /// The normal side is the half-space in the direction of the plane normal.
        /// The back side is the half-space in the opposite direction.</returns>
        public PlaneHalfSpace IntersectPlane(Plane plane)
        {
            PlaneHalfSpace planeHalfSpace = vertex1.IntersectPlane(plane);

            planeHalfSpace |= vertex2.IntersectPlane(plane);
            planeHalfSpace |= vertex3.IntersectPlane(plane);
            return(planeHalfSpace);
        }
コード例 #3
0
        /// <summary>
        /// Tests whether a triangle is 'outside' one of a set of planes.
        /// </summary>
        /// <param name="tri"></param>
        /// <param name="planes"></param>
        /// <returns>True iff triangle is 'outside' one of the planes</returns>
        static private bool IsTrianglesOutsidePlanes(Triangle tri, IEnumerable <Plane> planes)
        {
            // TODO: a triangle can be 'inside' all planes (each plane has at least one triangle vertex 'inside' the plane),
            // yet the triangle can still not intersect the volume defined by the planes.
            // Do we need to clip the triangle to each plane to figure out if any part of the triangle lies 'inside' all planes?

            foreach (var plane in planes)
            {
                PlaneHalfSpace side = tri.IntersectPlane(plane);
                if ((side & PlaneHalfSpace.NormalSide) == 0)
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #4
0
            public void RecursivePlaneSplit(int treeDepth, int maxTreeDepth, int maxGeometryPerNode, int parentSplitAxis)
            {
                Contract.Requires(treeDepth > 0);
                Contract.Requires(maxTreeDepth > 0);
                Contract.Requires(maxGeometryPerNode > 0);
                Contract.Requires(0 <= parentSplitAxis && parentSplitAxis <= 2);
                Contract.Requires(splittingPlane == null, "splitting-plane is null");
                Assert.IsTrue(normalSide == null, "normal-side is null");
                Assert.IsTrue(backSide == null, "back-side is null");
                Assert.IsTrue(geometry != null, "geometry collection is null");
                Assert.IsTrue(geometry.Count > 0, "geometry collection is empty");

                leafColor      = (uint)random.Next();
                totalTreeDepth = Math.Max(totalTreeDepth, treeDepth);


                if (treeDepth >= maxTreeDepth ||            // Have we made the tree deep enough?
                    geometry.Count <= maxGeometryPerNode)   // Stop splitting nodes when current node contains little enough geometry.
                {
                    leafNodes++;
                    ProcessLeafNode();
                    return;
                }

                // Pick an axis-aligned plane to split the current sector.
                // TODO: balance tree better by choosing splitting plane direction based on
                // longest bounding box length, or most even split of geometry?
                int axis;

#if SPLIT_LONGEST_AXIS
                Vector boxExtent = boundingBox.Max - boundingBox.Min;
                boxExtent = new Vector(Math.Abs(boxExtent.x), Math.Abs(boxExtent.y), Math.Abs(boxExtent.z));
                if (boxExtent.x > boxExtent.y)
                {
                    if (boxExtent.x > boxExtent.z)
                    {
                        axis = 0; // X-axis
                    }
                    else
                    {
                        axis = 2; // Z-axis
                    }
                }
                else
                {
                    if (boxExtent.y > boxExtent.z)
                    {
                        axis = 1; // Y-axis
                    }
                    else
                    {
                        axis = 2; // Z-axis
                    }
                }
#else
                // Split on the next axis after the parent's split axis (i.e. X -> Y -> Z -> X ...)
                axis = (parentSplitAxis + 1) % 3;
#endif

                Vector splitPt = boundingBox.Centre;
#if ADAPTIVE_SPLIT
                // Compute centroid of all triangle vertices in this node.
                Vector centroid    = new Vector(0, 0, 0);
                int    vertexCount = 0;
                foreach (Triangle tri in geometry)
                {
                    //if (boundingBox.ContainsPoint(tri.Vertex1))
                    //{
                    //    centroid += tri.Vertex1;
                    //    vertexCount++;
                    //}
                    //if (boundingBox.ContainsPoint(tri.Vertex2))
                    //{
                    //    centroid += tri.Vertex2;
                    //    vertexCount++;
                    //}
                    //if (boundingBox.ContainsPoint(tri.Vertex3))
                    //{
                    //    centroid += tri.Vertex3;
                    //    vertexCount++;
                    //}
                    centroid    += tri.Vertex1;
                    centroid    += tri.Vertex2;
                    centroid    += tri.Vertex3;
                    vertexCount += 3;
                }
                splitPt = centroid / vertexCount;
#endif

                // Create splitting plane.
                switch (axis)
                {
                case 0: splittingPlane = new Plane(splitPt, new Vector(1, 0, 0)); break;     // X-axis

                case 1: splittingPlane = new Plane(splitPt, new Vector(0, 1, 0)); break;     // Y-axis

                case 2: splittingPlane = new Plane(splitPt, new Vector(0, 0, 1)); break;     // Z-axis

                default: Assert.Fail("Unexpected axis index"); break;
                }

                // Copy all geometry from current node to the appropriate child nodes.
                var normalSideGeom = new List <Triangle>();
                var backSideGeom   = new List <Triangle>();
                foreach (Triangle geom in geometry)
                {
                    PlaneHalfSpace planeHalfSpace = geom.IntersectPlane(splittingPlane);
                    Assert.IsTrue((planeHalfSpace & ~(PlaneHalfSpace.NormalSide | PlaneHalfSpace.BackSide)) == 0,
                                  "Unexpected PlaneHalfSpace enumeration bit value");

                    if ((planeHalfSpace & PlaneHalfSpace.NormalSide) != 0)
                    {
                        normalSideGeom.Add(geom);
                    }
                    if ((planeHalfSpace & PlaneHalfSpace.BackSide) != 0)
                    {
                        backSideGeom.Add(geom);
                    }
                }

                // If either child node ends up with no geometry or all geometry, keep the geometry in the current node.
                // TODO: if we cannot split along this axis, attempt to split along the other two axes?
                bool rejectSplit = (normalSideGeom.Count == geometry.Count || backSideGeom.Count == geometry.Count);

#if LOG_SPLITS
                Logger.Log("Tree node: axis {0}, depth: {1}, {2} tri => {3},{4} {5}",
                           axis, treeDepth, geometry.Count, normalSideGeom.Count, backSideGeom.Count, rejectSplit ? "(rejected split)" : "");
#endif

                if (rejectSplit)
                {
                    // Throw away the child nodes, i.e. reverse the splitting of the current node.
                    splittingPlane = null;
                    leafNodes++;
                    ProcessLeafNode();
                    return;
                }

                // Delete all geometry from current node, so that geometry only exists in child nodes.
                geometry.Clear();

                // Create bounding boxes for child nodes.
                Vector backSideBoxMax   = boundingBox.Max;
                Vector normalSideBoxMin = boundingBox.Min;
                switch (axis)
                {
                case 0: backSideBoxMax.x = normalSideBoxMin.x = splitPt.x; break;     // X-axis

                case 1: backSideBoxMax.y = normalSideBoxMin.y = splitPt.y; break;     // Y-axis

                case 2: backSideBoxMax.z = normalSideBoxMin.z = splitPt.z; break;     // Z-axis

                default: Assert.Fail("Unexpected axis index"); break;
                }
                AxisAlignedBox backSideBox   = new AxisAlignedBox(boundingBox.Min, backSideBoxMax);
                AxisAlignedBox normalSideBox = new AxisAlignedBox(normalSideBoxMin, boundingBox.Max);

                // Create child nodes and recursively split them.
                //axis = (axis + 1) % 3;
                treeDepth++;
                if (normalSideGeom.Count > 0)
                {
                    normalSide = new Node(normalSideGeom, normalSideBox);
                    normalSide.RecursivePlaneSplit(treeDepth, maxTreeDepth, maxGeometryPerNode, axis);
                }
                if (backSideGeom.Count > 0)
                {
                    backSide = new Node(backSideGeom, backSideBox);
                    backSide.RecursivePlaneSplit(treeDepth, maxTreeDepth, maxGeometryPerNode, axis);
                }

                // Is current node a leaf node?
                if (normalSide == null && backSide == null)
                {
                    // Yes, so increment the leaf node count.
                    // TODO: we never seem to reach this code!
                    leafNodes++;
                    splittingPlane = null;
                    // TODO: Contracts analyser complains that this assert is always false, due to "initialisation of this.backSide" !?!
                    Contract.Assert(geometry.Count > 0, "Leaf node must contain some geometry");
                    Contract.Assert(splittingPlane == null, "Leaf node must not have a splitting plane");
                }
                else
                {
                    // No, current node is an internal node. Check that no internal node has any geometry.
                    Contract.Assert(geometry.Count == 0, "Internal node must not contain any geometry");
                    Contract.Assert(splittingPlane != null, "Internal node must have a splitting plane");
                }
            }