Exemple #1
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);
        }
Exemple #2
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);
        }
Exemple #3
0
        private Vec3F CalcTangent(Vec3F p1, Vec3F p2, Vec3F p3)
        {
            Vec3F v1       = (p1 - p2) / (p1 - p2).Length;
            Vec3F v2       = (p3 - p2) / (p3 - p2).Length;
            Vec3F bisector = v1 + v2;
            Vec3F normal   = Vec3F.Cross(v1, v2);

            if (normal.Length < 0.1e-5f) // 3 points  colinear
            {
                return(v2);
            }
            Vec3F tangent = Vec3F.Cross(normal, bisector);

            tangent = tangent / tangent.Length;
            return(tangent);
        }
Exemple #4
0
        /// <summary>
        /// Orthonormalizes the matrix</summary>
        /// <param name="m">The matrix to orthonormalize</param>
        public void OrthoNormalize(Matrix4F m)
        {
            Vec3F xAxis = new Vec3F(m.M11, m.M12, m.M13);
            Vec3F yAxis = new Vec3F(m.M21, m.M22, m.M23);
            Vec3F zAxis;

            zAxis = Vec3F.Cross(xAxis, yAxis);
            yAxis = Vec3F.Cross(zAxis, xAxis);

            xAxis = xAxis / xAxis.Length;
            yAxis = yAxis / yAxis.Length;
            zAxis = zAxis / zAxis.Length;

            M11 = xAxis.X; M12 = xAxis.Y; M13 = xAxis.Z;
            M21 = yAxis.X; M22 = yAxis.Y; M23 = yAxis.Z;
            M31 = zAxis.X; M32 = zAxis.Y; M33 = zAxis.Z;

            M41 = m.M41;
            M42 = m.M42;
            M43 = m.M43;
        }
Exemple #5
0
        public static void WritePolygon(
            Vector3[] pts,
            List <Vector3> pos, List <Vector3> normal, List <uint> indices)
        {
            // Calculate a normal for this face!
            ///////////////////////////////////////
            // We have good C++ code for fitting planes to faces.
            // But we don't have access to it from this code!

            var n = new Vector3(0.0f, 0.0f, 0.0f);

            for (uint c = 0; c < pts.Length - 2; ++c)
            {
                n += /*Vector3.Normalize*/ (Vector3.Cross(pts[c] - pts[c + 1], pts[c + 2] - pts[c + 1]));
            }

            // note that if we don't do the above normalize, then the contribution of
            // each triangle will be weighted by the length of the cross product (which is
            // proportional to the triangle area -- effectively weighting by triangle area).
            n = -Vector3.Normalize(n);

            var firstIndex = pos.Count;

            for (uint c = 0; c < pts.Length; ++c)
            {
                pos.Add(pts[c]);
                normal.Add(n);
            }

            for (uint c = 2; c < pts.Length; ++c)
            {
                indices.Add((uint)(firstIndex));
                indices.Add((uint)(firstIndex + c - 1));
                indices.Add((uint)(firstIndex + c));
            }
        }
Exemple #6
0
        public static void CreateCylinder(float rad1, float rad2, float height, uint slices, uint stacks,
                                          List <Vector3> pos, List <Vector3> normal, List <uint> indices)
        {
            float stackHeight = height / stacks;

            // Amount to increment radius as we move up each stack level from bottom to top.
            float radiusStep = (rad2 - rad1) / stacks;

            uint numRings = stacks + 1;

            // Compute vertices for each stack ring.
            for (uint i = 0; i < numRings; ++i)
            {
                float y = i * stackHeight;
                float r = rad1 + i * radiusStep;

                // Height and radius of next ring up.
                float y_next = (i + 1) * stackHeight;
                float r_next = rad1 + (i + 1) * radiusStep;

                // vertices of ring
                float dTheta = 2.0f * MathHelper.Pi / slices;
                for (uint j = 0; j <= slices; ++j)
                {
                    float c = (float)Math.Cos(j * dTheta);
                    float s = (float)Math.Sin(j * dTheta);

                    // tex coord if needed.
                    //float u = j/(float) slices;
                    //float v = 1.0f - (float) i/stacks;

                    // Partial derivative in theta direction to get tangent vector (this is a unit vector).
                    Vector3 T = new Vector3(-s, 0.0f, c);

                    // Compute tangent vector down the slope of the cone (if the top/bottom
                    // radii differ then we get a cone and not a true cylinder).
                    Vector3 P      = new Vector3(r * c, y, r * s);
                    Vector3 P_next = new Vector3(r_next * c, y_next, r_next * s);
                    Vector3 B      = P - P_next;
                    B.Normalize();


                    Vector3 N = Vector3.Cross(T, B);
                    N.Normalize();

                    P.Z *= -1;
                    N.Z *= -1;

                    pos.Add(P);
                    if (normal != null)
                    {
                        normal.Add(N);
                    }
                }
            }

            uint numRingVertices = slices + 1;

            // Compute indices for each stack.
            for (uint i = 0; i < stacks; ++i)
            {
                for (uint j = 0; j < slices; ++j)
                {
                    indices.Add(i * numRingVertices + j);
                    indices.Add((i + 1) * numRingVertices + j + 1);
                    indices.Add((i + 1) * numRingVertices + j);

                    indices.Add(i * numRingVertices + j);
                    indices.Add(i * numRingVertices + j + 1);
                    indices.Add((i + 1) * numRingVertices + j + 1);
                }
            }

            // build bottom cap.
            if (rad1 > 0)
            {
                uint baseIndex = (uint)pos.Count;


                // Duplicate cap vertices because the texture coordinates and normals differ.
                float y = 0;

                // vertices of ring
                float dTheta = 2.0f * MathHelper.Pi / slices;
                for (uint i = 0; i <= slices; ++i)
                {
                    float x = rad1 * (float)Math.Cos(i * dTheta);
                    float z = rad1 * (float)Math.Sin(i * dTheta);

                    // Map [-1,1]-->[0,1] for planar texture coordinates.
                    //float u = +0.5f * x / mBottomRadius + 0.5f;
                    //float v = -0.5f * z / mBottomRadius + 0.5f;
                    Vector3 p = new Vec3F(x, y, -z);
                    pos.Add(p);
                    if (normal != null)
                    {
                        normal.Add(new Vec3F(0.0f, -1.0f, 0.0f));
                    }
                }


                // cap center vertex
                pos.Add(new Vec3F(0.0f, y, 0.0f));
                if (normal != null)
                {
                    normal.Add(new Vec3F(0.0f, -1.0f, 0.0f));
                }
                // tex coord for center cap 0.5f, 0.5f


                // index of center vertex
                uint centerIndex = (uint)pos.Count - 1;

                for (uint i = 0; i < slices; ++i)
                {
                    indices.Add(centerIndex);
                    indices.Add(baseIndex + i + 1);
                    indices.Add(baseIndex + i);
                }
            }

            // build top cap.
            if (rad2 > 0)
            {
                uint baseIndex = (uint)pos.Count;

                // Duplicate cap vertices because the texture coordinates and normals differ.
                float y = height;

                // vertices of ring
                float dTheta = 2.0f * MathHelper.Pi / slices;
                for (uint i = 0; i <= slices; ++i)
                {
                    float x = rad2 * (float)Math.Cos(i * dTheta);
                    float z = rad2 * (float)Math.Sin(i * dTheta);

                    // Map [-1,1]-->[0,1] for planar texture coordinates.
                    //float u = +0.5f * x / mTopRadius + 0.5f;
                    //float v = -0.5f * z / mTopRadius + 0.5f;
                    pos.Add(new Vec3F(x, y, -z));
                    if (normal != null)
                    {
                        normal.Add(new Vec3F(0.0f, 1.0f, 0.0f));
                    }
                }

                // pos, norm, tex1 for cap center vertex
                pos.Add(new Vec3F(0.0f, y, 0.0f));
                if (normal != null)
                {
                    normal.Add(new Vec3F(0.0f, 1.0f, 0.0f));
                }
                // tex coord 0.5f, 0.5f


                // index of center vertex
                uint centerIndex = (uint)pos.Count - 1;
                for (uint i = 0; i < slices; ++i)
                {
                    indices.Add(centerIndex);
                    indices.Add(baseIndex + i);
                    indices.Add(baseIndex + i + 1);
                }
            }
        }
Exemple #7
0
 private void CalcPlaneNormal(int planeIndex, Vec3F u1, Vec3F u2)
 {
     m_planes[planeIndex].Normal = Vec3F.Cross(u1, u2);
     m_planes[planeIndex].Normal.Normalize();
     m_planes[planeIndex].Distance = 0;
 }
Exemple #8
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);
        }
Exemple #9
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);
        }