コード例 #1
0
ファイル: Triangle.cs プロジェクト: rioscode/raytracer
        /// <summary> Clip this triangle by a plane </summary>
        /// <param name="plane">The clipping plane to clip the triangle with</param>
        /// <returns>The points that are left after clipping the triangle</returns>
        public Vector3[] GetClippedPoints(AxisAlignedPlane plane)
        {
            Vector3     v0 = P1 - plane.Position, v1 = P2 - plane.Position, v2 = P3 - plane.Position, v3;
            const float clipEpsilon = 0.00001f, clipEpsilon2 = 0.01f;
            // Distances to the plane (this is an array parallel to v[], stored as a vec3)
            Vector3 dist = new Vector3(Vector3.Dot(v0, plane.Normal), Vector3.Dot(v1, plane.Normal), Vector3.Dot(v2, plane.Normal));

            if (dist.X < clipEpsilon2 && dist.Y < clipEpsilon2 && dist.Z < clipEpsilon2)
            {
                // Case 1 (all clipped)
                return(Array.Empty <Vector3>());
            }
            if (dist.X > -clipEpsilon && dist.Y > -clipEpsilon && dist.Z > -clipEpsilon)
            {
                // Case 2 (none clipped)
                return(new Vector3[] { v0, v1, v2 });
            }
            // There are either 1 or 2 vertices above the clipping plane
            bool above0 = dist.X >= 0;
            bool above1 = dist.Y >= 0;
            bool above2 = dist.Z >= 0;
            bool nextIsAbove;

            // Find the CCW - most vertex above the plane
            if (above1 && !above0)
            {
                // Cycle once CCW. Use v3 as a temp
                nextIsAbove = above2;
                v3          = v0; v0 = v1; v1 = v2; v2 = v3;
                dist        = new Vector3(dist.Y, dist.Z, dist.X);
            }
            else if (above2 && !above1)
            {
                // Cycle once CW. Use v3 as a temp
                nextIsAbove = above0;
                v3          = v2; v2 = v1; v1 = v0; v0 = v3;
                dist        = new Vector3(dist.Z, dist.X, dist.Y);
            }
            else
            {
                nextIsAbove = above1;
            }
            // We always need to clip v2 - v0
            v3 = Vector3.Lerp(v0, v2, dist[0] / (dist[0] - dist[2]));
            if (nextIsAbove)
            {
                // Case 3 (quadrilateral)
                v2 = Vector3.Lerp(v1, v2, dist[1] / (dist[1] - dist[2]));
                return(new Vector3[] { v0, v1, v2, v3 });
            }
            else
            {
                // Case 4 (triangle)
                v1 = Vector3.Lerp(v0, v1, dist[0] / (dist[0] - dist[1]));
                v2 = v3;
                return(new Vector3[] { v0, v1, v2 });
            }
        }
コード例 #2
0
        public void GetClippedPoints_AllClipped()
        {
            AxisAlignedPlane plane = new AxisAlignedPlane(new Vector3(0, 0, -1), Vector3.Zero);

            for (int i = 0; i < 100; i++)
            {
                Triangle  triangle = Utils.Random.Triangle(0f, 1f);
                Vector3[] points   = triangle.GetClippedPoints(plane);
                Assert.AreEqual(points.Length, 0);
            }
        }
コード例 #3
0
 public void Clip()
 {
     for (int i = 0; i < 100; i++)
     {
         Primitive         primitive  = Utils.Random.Sphere();
         Vector3[]         bounds     = primitive.Bounds;
         AxisAlignedPlane  plane      = new AxisAlignedPlane(Utils.Random.UnitVector(), primitive.Position);
         PrimitiveFragment fragment   = primitive.Clip(plane);
         Vector3[]         clipBounds = fragment.Bounds;
         Assert.IsTrue(bounds[0] != clipBounds[0] || bounds[1] != clipBounds[1]);
     }
 }
コード例 #4
0
 /// <summary> Clip the <see cref="PrimitiveFragment"/> by a <paramref name="plane"/></summary>
 /// <param name="plane">The <see cref="AxisAlignedPlane"/> to clip the <see cref="PrimitiveFragment"/> with</param>
 /// <returns>A new <see cref="PrimitiveFragment"/> with clipped bounds</returns>
 public override IEnumerable <PrimitiveFragment> Clip(AxisAlignedPlane plane)
 {
     foreach (IShape shape in Shape.Clip(plane))
     {
         if (shape == Shape)
         {
             yield return(this);
         }
         else
         {
             yield return(new PrimitiveFragment(Original, shape));
         }
     }
 }
コード例 #5
0
ファイル: Primitive.cs プロジェクト: atharkes/raytracer
 public virtual IEnumerable <ISceneObject> Clip(AxisAlignedPlane plane)
 {
     foreach (IShape shape in Shape.Clip(plane))
     {
         if (shape == Shape)
         {
             yield return(this);
         }
         else
         {
             yield return(new PrimitiveFragment(this, shape));
         }
     }
 }
コード例 #6
0
        /// <summary> Clip the AABB of the primitive with an axis-aligned plane </summary>
        /// <param name="plane">The plane to clip the AABB with</param>
        /// <returns>The bounds of the clipped AABB</returns>
        public virtual PrimitiveFragment?Clip(AxisAlignedPlane plane)
        {
            Vector3[] bounds = Bounds;
            Vector3   min    = bounds[0];
            Vector3   max    = bounds[1];

            if (plane.Normal == Vector3.UnitX)
            {
                min.X = Math.Max(min.X, plane.Position.X);
            }
            else if (plane.Normal == -Vector3.UnitX)
            {
                max.X = Math.Min(max.X, plane.Position.X);
            }
            else if (plane.Normal == Vector3.UnitY)
            {
                min.Y = Math.Max(min.Y, plane.Position.Y);
            }
            else if (plane.Normal == -Vector3.UnitY)
            {
                max.Y = Math.Min(max.Y, plane.Position.Y);
            }
            else if (plane.Normal == Vector3.UnitZ)
            {
                min.Z = Math.Max(min.Z, plane.Position.Z);
            }
            else if (plane.Normal == -Vector3.UnitZ)
            {
                max.Z = Math.Min(max.Z, plane.Position.Z);
            }
            else
            {
                throw new ArgumentException("Can't clip if plane is not axis-aligned");
            }
            if (max.X < min.X || max.Y < min.Y || max.Z < min.Z)
            {
                return(null);
            }
            else
            {
                return(new PrimitiveFragment(this, new Vector3[] { min, max }));
            }
        }
コード例 #7
0
        public void GetClippedPoints_TwoClipped()
        {
            Vector3          P1       = new Vector3(1, 0, 1);
            Vector3          P2       = new Vector3(0, 0, 1);
            Vector3          P3       = new Vector3(0, 0, -1);
            Triangle         triangle = new Triangle(P1, P2, P3);
            AxisAlignedPlane plane    = new AxisAlignedPlane(new Vector3(0, 0, 1), Vector3.Zero);
            List <Vector3>   points   = new List <Vector3>(triangle.GetClippedPoints(plane));

            Assert.AreEqual(points.Count, 4);
            CollectionAssert.Contains(points, triangle.P1);
            CollectionAssert.Contains(points, triangle.P2);
            CollectionAssert.DoesNotContain(points, triangle.P3);
            Vector3 P31 = Vector3.Lerp(P3, P2, 0.5f);
            Vector3 P32 = Vector3.Lerp(P3, P1, 0.5f);

            CollectionAssert.Contains(points, P31);
            CollectionAssert.Contains(points, P32);
        }
コード例 #8
0
        public void GetClippedPoints_OneClipped()
        {
            Vector3          P1       = new Vector3(1, 0, 1);
            Vector3          P2       = new Vector3(0, 0, 1);
            Vector3          P3       = new Vector3(0, 0, -1);
            Triangle         triangle = new Triangle(P1, P2, P3);
            AxisAlignedPlane plane    = new AxisAlignedPlane(new Vector3(0, 0, -1), Vector3.Zero);

            Vector3[] points = triangle.GetClippedPoints(plane);
            Assert.AreEqual(points.Length, 3);
            CollectionAssert.DoesNotContain(points, triangle.P1);
            CollectionAssert.DoesNotContain(points, triangle.P2);
            CollectionAssert.Contains(points, triangle.P3);
            Vector3 P11 = Vector3.Lerp(P1, P3, 0.5f);
            Vector3 P21 = Vector3.Lerp(P2, P3, 0.5f);

            CollectionAssert.Contains(points, P11);
            CollectionAssert.Contains(points, P21);
        }
コード例 #9
0
ファイル: AxisAlignedBox.cs プロジェクト: atharkes/raytracer
        /// <summary> Clip the <see cref="AxisAlignedBox"/> by a <paramref name="plane"/> </summary>
        /// <param name="plane">The <see cref="AxisAlignedPlane"/> to clip the <see cref="AxisAlignedBox"/> with</param>
        /// <returns>A new clipped <see cref="AxisAlignedBox"/> if it's not clipped entirely</returns>
        public IEnumerable <AxisAlignedBox> Clip(AxisAlignedPlane plane)
        {
            Position3 minCorner = MinCorner;
            Position3 maxCorner = MaxCorner;

            if (plane.Normal == Normal3.UnitX)
            {
                minCorner = new(Position1.Max(MinCorner.X, plane.Position.X), MinCorner.Y, MinCorner.Z);
            }
            else if (plane.Normal == -Normal3.UnitX)
            {
                maxCorner = new(Position1.Min(MinCorner.X, plane.Position.X), MaxCorner.Y, MaxCorner.Z);
            }
            else if (plane.Normal == Normal3.UnitY)
            {
                minCorner = new(MinCorner.X, Position1.Max(MinCorner.Y, plane.Position.Y), MinCorner.Z);
            }
            else if (plane.Normal == -Normal3.UnitY)
            {
                maxCorner = new(MaxCorner.X, Position1.Min(MaxCorner.Y, plane.Position.Y), MaxCorner.Z);
            }
            else if (plane.Normal == Normal3.UnitZ)
            {
                minCorner = new(MinCorner.X, MinCorner.Y, Position1.Max(MinCorner.Z, plane.Position.Z));
            }
            else if (plane.Normal == -Normal3.UnitZ)
            {
                maxCorner = new(MaxCorner.X, MaxCorner.Y, Position1.Min(MaxCorner.Z, plane.Position.Z));
            }
            if (minCorner == MinCorner && maxCorner == MaxCorner)
            {
                yield return(this);
            }
            else if (minCorner.X < maxCorner.X && minCorner.Y < maxCorner.Y && minCorner.Z < maxCorner.Z)
            {
                yield return(new AxisAlignedBox(minCorner, maxCorner));
            }
        }
コード例 #10
0
ファイル: Aggregate.cs プロジェクト: atharkes/raytracer
 public IEnumerable <ISceneObject> Clip(AxisAlignedPlane plane)
 {
     throw new NotImplementedException("Split items and clip items on the border");
 }