Beispiel #1
0
        /// <summary>
        /// Finds the intersection point of the ray with the given plane. Checks
        /// for the ray being parallel with the plane or the ray pointing away
        /// from the plane</summary>
        /// <param name="plane">Must be constructed "by the rules" of Plane3F</param>
        /// <param name="intersectionPoint">The resulting intersection point or
        /// the zero-point if there was no intersection</param>
        /// <returns>True if the ray points towards the plane and intersects it</returns>
        public bool IntersectPlane(Plane3F plane, out Vec3F intersectionPoint)
        {
            // both the normal and direction must be unit vectors.
            float cos = Vec3F.Dot(plane.Normal, Direction);

            if (Math.Abs(cos) > 0.0001f)
            {
                // dist > 0 means "on the same side as the normal", aka, "the front".
                float dist = plane.SignedDistance(Origin);
                // There are two cases for the ray shooting away from the plane:
                // 1. If the ray is in front of the plane and pointing away,
                //  then 'cos' and 'dist' are both > 0.
                // 2. If the ray is in back of the plane and pointing away,
                //  then 'cos' and 'dist' are both < 0.
                // So, if the signs are the same, then there's no intersection.
                // So, if 'cos' * 'dist' is positive, then there's no intersection.
                if (cos * dist < 0.0)
                {
                    // There are two cases for the ray hitting the plane:
                    // 1. Origin is behind the plane, so the ray and normal are aligned
                    //  and 'dist' is < 0. We need to negate 'dist'.
                    // 2. Origin is in front of the plane, so the ray needs to be negated
                    //  so that cos(angle-180) is calculated. 'dist' is > 0.
                    // Either way, we've got a -1 thrown into the mix. Tricky!
                    float t = -dist / cos;
                    intersectionPoint = Origin + (Direction * t);
                    return(true);
                }
            }
            intersectionPoint = new Vec3F(0, 0, 0);
            return(false);
        }
Beispiel #2
0
        /// <summary>
        /// Finds the intersection point of the ray with the given plane. The ray is
        /// treated as an infinite line, so it will intersect going "forwards" or
        /// "backwards". The plane equation is the opposite of that for Plane3F. For
        /// all points 'p' on the plane: planeNormal * p + D = 0</summary>
        /// <param name="planeNormal">Plane normal</param>
        /// <param name="planeDistance">Plane constant</param>
        /// <returns>Intersection point of ray with plane</returns>
        /// <remarks>Does not check for ray parallel to plane</remarks>
        public Vec3F IntersectPlane(Vec3F planeNormal, float planeDistance)
        {
            float t = -(Vec3F.Dot(planeNormal, Origin) + planeDistance) /
                      Vec3F.Dot(planeNormal, Direction);

            return(Origin + (Direction * t));
        }
Beispiel #3
0
        /// <summary>
        /// Returns the point on this ray resulting from projecting 'point' onto this ray.
        /// This is also the same as finding the closest point on this ray to 'point'.</summary>
        /// <param name="point">Point to project onto this ray</param>
        /// <returns>Closest point on this ray to 'point'</returns>
        public Vec3F ProjectPoint(Vec3F point)
        {
            Vec3F normalizedDir = Vec3F.Normalize(Direction);
            float distToX       = Vec3F.Dot(point - Origin, normalizedDir);
            Vec3F x             = Origin + distToX * normalizedDir;

            return(x);
        }
Beispiel #4
0
        /// <summary>
        /// Constructs a plane from 3 non-linear points on the plane, such that
        /// Normal * p = Distance</summary>
        /// <param name="p1">First point</param>
        /// <param name="p2">Second point</param>
        /// <param name="p3">Third point</param>
        public Plane3F(Vec3F p1, Vec3F p2, Vec3F p3)
        {
            Vec3F d12    = p2 - p1;
            Vec3F d13    = p3 - p1;
            Vec3F normal = Vec3F.Cross(d12, d13);

            Normal   = Vec3F.Normalize(normal);
            Distance = Vec3F.Dot(Normal, p1);
        }
Beispiel #5
0
        /// <summary>
        /// Tests if a specified ray intersects this sphere</summary>
        /// <param name="ray">The ray, with an origin and unit-length direction. Only intersections in
        /// front of the ray count.</param>
        /// <param name="x">The intersection point, if there was an intersection</param>
        /// <returns>True iff ray intersects this sphere</returns>
        /// <remarks>Algorithm is from _Real-Time Rendering_, p. 299</remarks>
        public bool Intersects(Ray3F ray, out Vec3F x)
        {
            // vector from ray's origin to sphere's center
            Vec3F oToC = Center - ray.Origin;

            // 'd' is the distance from the ray's origin to the nearest point on the ray to Center.
            // Assumes that Direction has unit length.
            float d = Vec3F.Dot(oToC, ray.Direction);

            // distToCenterSquared is the distance from ray's origin to Center, squared.
            float distToCenterSquared = oToC.LengthSquared;
            float radiusSquared       = Radius * Radius;

            // if the sphere is behind the ray and the ray's origin is outside the sphere...
            if (d < 0 && distToCenterSquared > radiusSquared)
            {
                x = new Vec3F();
                return(false);
            }

            // 'm' is the distance from the ray to the center. Pythagorean's theorem.
            float mSquared = distToCenterSquared - d * d;

            if (mSquared > radiusSquared)
            {
                x = new Vec3F();
                return(false);
            }

            // 'q' is the distance from the first intersection point to the nearest point
            //  on the ray to Center. Pythagorean's theorem.
            float q = (float)Math.Sqrt(radiusSquared - mSquared);

            // 't' is the distance along 'ray' to the point of first intersection.
            float t;

            if (distToCenterSquared > radiusSquared)
            {
                // ray's origin is outside the sphere.
                t = d - q;
            }
            else
            {
                // ray's origin is inside the sphere.
                t = d + q;
            }

            // the point of intersection is ray's origin plus distance along ray's direction
            x = ray.Origin + t * ray.Direction;
            return(true);
        }
Beispiel #6
0
        /// <summary>
        /// Tests if any part of the polygon is inside this frustum. Errs on the side of inclusion.
        /// The polygon and the frustum and the eye must be in the same space -- probably object space
        /// to avoid the expense of transforming all the polygons into view space unnecessarily.</summary>
        /// <param name="vertices">A polygon. Can be non-convex and non-planar for the frustum test.
        /// Must be convex and planar for backface culling.</param>
        /// <param name="eye">The camera's eye associated with this frustum. Is only used if 'backfaceCull'
        /// is 'true'.</param>
        /// <param name="backfaceCull">Should back-facing polygons always be excluded?</param>
        /// <returns>True iff any part of the polygon is inside this frustum</returns>
        public bool ContainsPolygon(Vec3F[] vertices, Vec3F eye, bool backfaceCull)
        {
            // If all of the points are outside any one plane, then the polygon is not contained.
            for (int p = 0; p < 6; p++)
            {
                int v = 0;
                for (; v < vertices.Length; v++)
                {
                    float dist = m_planes[p].SignedDistance(vertices[v]);
                    if (dist > 0.0f)
                    {
                        break;
                    }
                }
                if (v == vertices.Length)
                {
                    return(false);
                }
            }

            if (backfaceCull)
            {
                // First calculate polygon normal, pointing "out from" the visible side.
                Vec3F normal = new Vec3F();
                for (int i = 2; i < vertices.Length; i++)
                {
                    normal = Vec3F.Cross(vertices[0] - vertices[1],
                                         vertices[i] - vertices[1]);

                    // Make sure that these 3 verts are not collinear
                    if (normal.LengthSquared != 0)
                    {
                        break;
                    }
                }

                // We can't use the near plane's normal, since it may no longer be pointing in the correct
                // direction (due to non-uniform scalings, shear transforms, etc.).
                if (Vec3F.Dot(normal, vertices[0] - eye) <= 0)
                {
                    return(false);
                }
            }

            // This is an approximation. To be absolutely sure, we'd have to test the 8 points
            // of this frustum against the plane of the polygon and against the plane of each edge,
            // perpendicular to the polygon plane.
            return(true);
        }
Beispiel #7
0
        private Vec3F CalcEndTangents(Vec3F p1, Vec3F p2, Vec3F p2Tangent)
        {
            Vec3F v1    = p1 - p2;
            float v1Len = v1.Length;
            Vec3F u1    = v1 / v1Len;

            // Make sure that v1 and p2Tangent are facing the same way
            if (Vec3F.Dot(v1, p2Tangent) < 0)
            {
                p2Tangent = -p2Tangent;
            }

            // calc t for which the tangent vector t*p2Tangent is projected on 1/2 of v1
            float t       = (0.5f * v1Len) / Vec3F.Dot(p2Tangent, u1);
            Vec3F p3      = p2 + (p2Tangent * t);
            Vec3F tangent = (p3 - p1) / (p3 - p1).Length;

            return(tangent);
        }
Beispiel #8
0
        private void BuildCurves()
        {
            m_curves.Clear();

            if (Count > 1)
            {
                if (Count == 2)
                {
                    BuildInitialCurveFrom2Points();
                }
                else
                {
                    Vec3F   zeroVec  = new Vec3F(0, 0, 0);
                    Vec3F[] tangents = CalcPointTangents();

                    for (int i = 1; i < Count; i++)
                    {
                        Vec3F chord  = this[i].Position - this[i - 1].Position;
                        float segLen = chord.Length * 0.333f;

                        Vec3F[] points = new Vec3F[4];
                        points[0] = this[i - 1].Position;
                        points[3] = this[i].Position;

                        // calc points[1]
                        if (this[i - 1].Tangent2 != zeroVec)
                        {
                            points[1] = this[i - 1].Position + this[i - 1].Tangent2;
                        }
                        else
                        {
                            Vec3F tangent = tangents[i - 1];
                            if (Vec3F.Dot(chord, tangent) < 0)
                            {
                                tangent = -tangent;
                            }

                            points[1] = this[i - 1].Position + (tangent * segLen);
                        }

                        // calc points[2]
                        if (this[i].Tangent1 != zeroVec)
                        {
                            points[2] = this[i].Position + this[i].Tangent1;
                        }
                        else
                        {
                            Vec3F tangent = tangents[i];
                            if (Vec3F.Dot(-chord, tangent) < 0)
                            {
                                tangent = -tangent;
                            }

                            points[2] = this[i].Position + (tangent * segLen);
                        }

                        BezierCurve curve = new BezierCurve(points);
                        m_curves.Add(curve);
                    }

                    // Calculate last curve if is closed
                    if (m_isClosed)
                    {
                        Vec3F[] points = new Vec3F[4];
                        points[0] = this[Count - 1].Position;
                        points[3] = this[0].Position;
                        float tanLen = (points[3] - points[0]).Length / 3.0f;

                        Vec3F v = m_curves[m_curves.Count - 1].ControlPoints[2] - points[0];
                        v         = v / v.Length;
                        points[1] = points[0] - (v * tanLen);

                        v         = m_curves[0].ControlPoints[1] - points[3];
                        v         = v / v.Length;
                        points[2] = points[3] - (v * tanLen);

                        BezierCurve curve = new BezierCurve(points);
                        m_curves.Add(curve);
                    }
                }
            }
        }
Beispiel #9
0
        private bool IsLeftOf(TriVx v0, TriVx v1, TriVx v2, Vec3F normal)
        {
            Vec3F cross = Vec3F.Cross(v1.V - v0.V, v2.V - v0.V);

            return(Vec3F.Dot(cross, normal) > 0.0f);
        }
Beispiel #10
0
 /// <summary>
 /// Returns the signed distance along the ray from the ray's origin to the projection of 'p'
 /// onto this ray</summary>
 /// <param name="p">Point to be projected onto this ray</param>
 /// <returns>Signed distance along the ray, from the ray's origin to the projected point.
 /// A negative number means that 'p' falls "behind" the ray.</returns>
 public float GetDistanceToProjection(Vec3F p)
 {
     return(Vec3F.Dot(p - Origin, Direction));
 }
Beispiel #11
0
        /// <summary>
        /// Finds the intersection point of the ray with the given convex polygon, if any. Returns the nearest
        /// vertex of the polygon to the intersection point. Can optionally backface cull the polygon.
        /// For backface culling, the front of the polygon is considered to be the side that has
        /// the vertices ordered counter-clockwise.</summary>
        /// <param name="vertices">Polygon vertices</param>
        /// <param name="intersectionPoint">Intersection point</param>
        /// <param name="nearestVert">Nearest polygon vertex to the point of intersection</param>
        /// <param name="normal">Normal unit-length vector, facing out from the side whose
        /// vertices are ordered counter-clockwise</param>
        /// <param name="backFaceCull">True if backface culling should be done</param>
        /// <returns>True iff the ray intersects the polygon</returns>
        public bool IntersectPolygon(Vec3F[] vertices, out Vec3F intersectionPoint,
                                     out Vec3F nearestVert, out Vec3F normal, bool backFaceCull)
        {
            bool intersects = true;
            int  sign       = 0;

            normal = new Vec3F();

            // First calc polygon normal
            for (int i = 2; i < vertices.Length; i++)
            {
                normal = Vec3F.Cross(vertices[i] - vertices[1], vertices[0] - vertices[1]);

                // Make sure that these 3 verts are not collinear
                float lengthSquared = normal.LengthSquared;
                if (lengthSquared != 0)
                {
                    normal *= (1.0f / (float)Math.Sqrt(lengthSquared));
                    break;
                }
            }

            if (backFaceCull)
            {
                if (Vec3F.Dot(normal, Direction) >= 0.0)
                {
                    intersectionPoint = new Vec3F();
                    nearestVert       = new Vec3F();
                    return(false);
                }
            }

            // Build plane and check if the ray intersects the plane.
            intersects = IntersectPlane(
                new Plane3F(normal, vertices[1]),
                out intersectionPoint);

            // Now check all vertices against intersection point
            for (int i = 0; i < vertices.Length && intersects; i++)
            {
                int i1 = i;
                int i0 = (i == 0 ? vertices.Length - 1 : i - 1);

                Vec3F cross = Vec3F.Cross(vertices[i1] - vertices[i0],
                                          intersectionPoint - vertices[i0]);

                // Check if edge and intersection vectors are collinear
                if (cross.LengthSquared == 0.0f)
                {
                    // check if point is on edge
                    intersects =
                        ((vertices[i1] - vertices[i0]).LengthSquared >=
                         (intersectionPoint - vertices[i0]).LengthSquared);

                    break;
                }
                else
                {
                    float dot = Vec3F.Dot(cross, normal);

                    if (i == 0)
                    {
                        sign = Math.Sign(dot);
                    }
                    else if (Math.Sign(dot) != sign)
                    {
                        intersects = false;
                    }
                }
            }

            // if we have a definite intersection, find the closest snap-to vertex.
            if (intersects)
            {
                nearestVert = vertices[0];
                float nearestDistSqr = (intersectionPoint - nearestVert).LengthSquared;
                for (int i = 1; i < vertices.Length; i++)
                {
                    float distSqr = (vertices[i] - intersectionPoint).LengthSquared;
                    if (distSqr < nearestDistSqr)
                    {
                        nearestDistSqr = distSqr;
                        nearestVert    = vertices[i];
                    }
                }
            }
            else
            {
                nearestVert = s_blankPoint;
            }

            return(intersects);
        }
Beispiel #12
0
 /// <summary>
 /// Returns the signed distance from this plane. This only works if the plane equation is
 /// Normal * p = Distance for any point 'p' on the plane. A positive result means that
 /// the point is on the same side of the plane that the normal is "on".</summary>
 /// <param name="point">Mathematical point</param>
 /// <returns>Signed distance from 'point' to this plane. Positive means "in front".</returns>
 public float SignedDistance(Vec3F point)
 {
     return(Vec3F.Dot(Normal, point) - Distance);
 }
Beispiel #13
0
 /// <summary>
 /// Constructs a plane from normal and point on plane, such that Normal * p = Distance</summary>
 /// <param name="normal">Normal. Should be a unit vector.</param>
 /// <param name="pointOnPlane">Point on plane</param>
 public Plane3F(Vec3F normal, Vec3F pointOnPlane)
 {
     Normal   = normal;
     Distance = Vec3F.Dot(normal, pointOnPlane);
 }