/// <summary>
        /// Recalculates the normals based on vertex positions.
        /// </summary>
        public void CalculateNormals()
        {
            if (Vertices.Count < 3)
            {
                return;
            }

            Vector3[] normals = new Vector3[Vertices.Count];
            for (int i = 0; i < normals.Length; i++)
            {
                normals[i] = new Vector3(0, 0, 0);
            }

            List <uint> f = Faces;

            for (int i = 0; i < f.Count; i += 3)
            {
                STVertex v1  = Vertices[(int)f[i]];
                STVertex v2  = Vertices[(int)f[i + 1]];
                STVertex v3  = Vertices[(int)f[i + 2]];
                Vector3  nrm = CalculateNormal(v1, v2, v3);

                normals[f[i + 0]] += nrm * (nrm.Length / 2);
                normals[f[i + 1]] += nrm * (nrm.Length / 2);
                normals[f[i + 2]] += nrm * (nrm.Length / 2);
            }

            for (int i = 0; i < normals.Length; i++)
            {
                Vertices[i].Normal = normals[i].Normalized();
            }
        }
        public float DistanceTo(STVertex vertex)
        {
            float deltaX = vertex.Position.X - Position.X;
            float deltaY = vertex.Position.Y - Position.Y;
            float deltaZ = vertex.Position.Z - Position.Z;

            return((float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ));
        }
        private Vector3 CalculateNormal(STVertex v1, STVertex v2, STVertex v3)
        {
            Vector3 U = v2.Position - v1.Position;
            Vector3 V = v3.Position - v1.Position;

            // Don't normalize here, so surface area can be calculated.
            return(Vector3.Cross(U, V));
        }
 public STVertex(STVertex vertex)
 {
     Position    = vertex.Position;
     Normal      = vertex.Normal;
     TexCoords   = vertex.TexCoords;
     Colors      = vertex.Colors;
     Tangent     = vertex.Tangent;
     Bitangent   = vertex.Bitangent;
     BoneWeights = vertex.BoneWeights;
     BoneIndices = vertex.BoneIndices;
     BoneNames   = vertex.BoneNames;
 }
        private void ApplyTanBitanArray(Vector3[] tanArray, Vector3[] bitanArray)
        {
            if (Vertices.Count < 3)
            {
                return;
            }

            for (int i = 0; i < Vertices.Count; i++)
            {
                STVertex v        = Vertices[i];
                Vector3  newTan   = tanArray[i];
                Vector3  newBitan = bitanArray[i];

                // The tangent and bitangent should be orthogonal to the normal.
                // Bitangents are not calculated with a cross product to prevent flipped shading  with mirrored normal maps.
                v.Tangent    = new Vector4(Vector3.Normalize(newTan - v.Normal * Vector3.Dot(v.Normal, newTan)), 1);
                v.Bitangent  = new Vector4(Vector3.Normalize(newBitan - v.Normal * Vector3.Dot(v.Normal, newBitan)), 1);
                v.Bitangent *= -1;
            }
        }
        private void CalculateTanBitanArrays(List <uint> faces, Vector3[] tanArray, Vector3[] bitanArray, int uvSet = 0)
        {
            if (Vertices.Count < 3 || faces.Count <= 0)
            {
                return;
            }

            for (int i = 0; i < faces.Count; i += 3)
            {
                STVertex v1 = Vertices[(int)faces[i]];
                STVertex v2 = Vertices[(int)faces[i + 1]];
                STVertex v3 = Vertices[(int)faces[i + 2]];

                float x1 = v2.Position.X - v1.Position.X;
                float x2 = v3.Position.X - v1.Position.X;
                float y1 = v2.Position.Y - v1.Position.Y;
                float y2 = v3.Position.Y - v1.Position.Y;
                float z1 = v2.Position.Z - v1.Position.Z;
                float z2 = v3.Position.Z - v1.Position.Z;

                float s1, s2, t1, t2;

                s1 = v2.TexCoords[uvSet].X - v1.TexCoords[uvSet].X;
                s2 = v3.TexCoords[uvSet].X - v1.TexCoords[uvSet].X;
                t1 = v2.TexCoords[uvSet].Y - v1.TexCoords[uvSet].Y;
                t2 = v3.TexCoords[uvSet].Y - v1.TexCoords[uvSet].Y;

                float div = (s1 * t2 - s2 * t1);
                float r   = 1.0f / div;

                // Fix +/- infinity from division by 0.
                if (r == float.PositiveInfinity || r == float.NegativeInfinity)
                {
                    r = 1.0f;
                }

                float   sX = t2 * x1 - t1 * x2;
                float   sY = t2 * y1 - t1 * y2;
                float   sZ = t2 * z1 - t1 * z2;
                Vector3 s  = new Vector3(sX, sY, sZ) * r;

                float   tX = s1 * x2 - s2 * x1;
                float   tY = s1 * y2 - s2 * y1;
                float   tZ = s1 * z2 - s2 * z1;
                Vector3 t  = new Vector3(tX, tY, tZ) * r;

                // Prevents black tangents or bitangents due to having vertices with the same UV coordinates.
                float delta = 0.00075f;
                bool  sameU, sameV;

                sameU = (Math.Abs(v1.TexCoords[uvSet].X - v2.TexCoords[uvSet].X) < delta) &&
                        (Math.Abs(v2.TexCoords[uvSet].X - v3.TexCoords[uvSet].X) < delta);

                sameV = (Math.Abs(v1.TexCoords[uvSet].Y - v2.TexCoords[uvSet].Y) < delta) &&
                        (Math.Abs(v2.TexCoords[uvSet].Y - v3.TexCoords[uvSet].Y) < delta);

                if (sameU || sameV)
                {
                    // Let's pick some arbitrary tangent vectors.
                    s = new Vector3(1, 0, 0);
                    t = new Vector3(0, 1, 0);
                }

                // Average tangents and bitangents.
                tanArray[faces[i]]     += s;
                tanArray[faces[i + 1]] += s;
                tanArray[faces[i + 2]] += s;

                bitanArray[faces[i]]     += t;
                bitanArray[faces[i + 1]] += t;
                bitanArray[faces[i + 2]] += t;
            }
        }