Beispiel #1
0
        public static void CalculateTangentFrames(GeometryContent geom, string textureCoordinateChannelName, string tangentChannelName, string binormalChannelName)
        {
            var verts    = geom.Vertices;
            var indices  = geom.Indices;
            var channels = geom.Vertices.Channels;

            var normals = channels.Get <Vector3>(VertexChannelNames.Normal(0));
            var uvs     = channels.Get <Vector2>(textureCoordinateChannelName);

            Vector3[] tangents, bitangents;
            CalculateTangentFrames(verts.Positions, indices, normals, uvs, out tangents, out bitangents);

            // All the indices are 1:1 with the others, so we
            // can just add the new channels in place.

            if (!string.IsNullOrEmpty(tangentChannelName))
            {
                channels.Add(tangentChannelName, tangents);
            }

            if (!string.IsNullOrEmpty(binormalChannelName))
            {
                channels.Add(binormalChannelName, bitangents);
            }
        }
Beispiel #2
0
        private int SetupVertexDeclaration(VertexBufferContent result)
        {
            var offset = 0;

            // We always have a position channel
            result.VertexDeclaration.VertexElements.Add(new VertexElement(offset, VertexElementFormat.Vector3,
                                                                          VertexElementUsage.Position, 0));
            offset += VertexElementFormat.Vector3.GetTypeSize();

            // Optional channels
            foreach (var channel in Channels)
            {
                VertexElementFormat format;
                VertexElementUsage  usage;

                // Try to determine the vertex format
                // TODO: Add support for additional formats as they become testable
                if (channel.ElementType == typeof(Vector3))
                {
                    format = VertexElementFormat.Vector3;
                }
                else if (channel.ElementType == typeof(Vector2))
                {
                    format = VertexElementFormat.Vector2;
                }
                else
                {
                    throw new InvalidContentException("Unrecognized vertex content type.");
                }

                // Try to determine the vertex usage
                if (!VertexChannelNames.TryDecodeUsage(channel.Name, out usage))
                {
                    throw new InvalidContentException("Unknown vertex element usage.");
                }

                // Try getting the usage index
                var usageIndex = VertexChannelNames.DecodeUsageIndex(channel.Name);

                result.VertexDeclaration.VertexElements.Add(new VertexElement(offset, format, usage, usageIndex));
                offset += format.GetTypeSize();
                result.VertexDeclaration.VertexStride = offset;
            }
            return(offset);
        }
Beispiel #3
0
        /// <summary>
        /// Generates vertex normals by accumulation of triangle face normals.
        /// </summary>
        /// <param name="geom">The geometry which will recieve the normals.</param>
        /// <param name="overwriteExistingNormals">Overwrite or skip over geometry with existing normals.</param>
        /// <remarks>
        /// We use a "Mean Weighted Equally" method generate vertex normals from triangle
        /// face normals.  If normal cannot be calculated from the geometry we set it to zero.
        /// </remarks>
        public static void CalculateNormals(GeometryContent geom, bool overwriteExistingNormals)
        {
            // Look for an existing normals channel.
            var channel = geom.Vertices.Channels.Get <Vector3>(VertexChannelNames.Normal());

            if (channel == null)
            {
                // We don't have existing normals, so add a new channel.
                channel = geom.Vertices.Channels.Add <Vector3>(VertexChannelNames.Normal(), null);
            }
            else
            {
                // If we're not supposed to overwrite the existing
                // normals then we're done here.
                if (!overwriteExistingNormals)
                {
                    return;
                }
            }

            var positionIndices = geom.Vertices.PositionIndices;

            Debug.Assert(positionIndices.Count == channel.Count, "The position and channel sizes were different!");

            // Accumulate all the triangle face normals for each vertex.
            var normals = new Vector3[positionIndices.Count];

            for (var i = 0; i < geom.Indices.Count; i += 3)
            {
                var ia = geom.Indices[i + 0];
                var ib = geom.Indices[i + 1];
                var ic = geom.Indices[i + 2];

                var aa = geom.Vertices.Positions[ia];
                var bb = geom.Vertices.Positions[ib];
                var cc = geom.Vertices.Positions[ic];

                var faceNormal = Vector3.Cross(cc - bb, bb - aa);
                var len        = faceNormal.Length();
                if (len > 0.0f)
                {
                    faceNormal = faceNormal / len;

                    // We are using the "Mean Weighted Equally" method where each
                    // face has an equal weight in the final normal calculation.
                    //
                    // We could maybe switch to "Mean Weighted by Angle" which is said
                    // to look best in most cases, but is more expensive to calculate.
                    //
                    // There is also an idea of weighting by triangle area, but IMO the
                    // triangle area doesn't always have a direct relationship to the
                    // shape of a mesh.
                    //
                    // For more ideas see:
                    //
                    // "A Comparison of Algorithms for Vertex Normal Computation"
                    // by Shuangshuang Jin, Robert R. Lewis, David West.
                    //

                    normals[positionIndices[ia]] += faceNormal;
                    normals[positionIndices[ib]] += faceNormal;
                    normals[positionIndices[ic]] += faceNormal;
                }
            }

            // Normalize the gathered vertex normals.
            for (var i = 0; i < normals.Length; i++)
            {
                var normal = normals[i];
                var len    = normal.Length();
                if (len > 0.0f)
                {
                    normals[i] = normal / len;
                }
                else
                {
                    // TODO: It would be nice to be able to log this to
                    // the pipeline so that it can be fixed in the model.

                    // TODO: We could maybe void this by a better algorithm
                    // above for generating the normals.

                    // We have a zero length normal.  You can argue that putting
                    // anything here is better than nothing, but by leaving it to
                    // zero it allows the caller to detect this and react to it.
                    normals[i] = Vector3.Zero;
                }
            }

            // Set the new normals on the vertex channel.
            for (var i = 0; i < channel.Count; i++)
            {
                channel[i] = normals[positionIndices[i]];
            }
        }
Beispiel #4
0
        private int SetupVertexDeclaration(VertexBufferContent result)
        {
            var offset = 0;

            // We always have a position channel
            result.VertexDeclaration.VertexElements.Add(new VertexElement(offset, VertexElementFormat.Vector3,
                                                                          VertexElementUsage.Position, 0));
            offset += VertexElementFormat.Vector3.GetSize();

            // Optional channels
            foreach (var channel in Channels)
            {
                VertexElementFormat format;
                VertexElementUsage  usage;

                // Try to determine the vertex format
                if (channel.ElementType == typeof(Single))
                {
                    format = VertexElementFormat.Single;
                }
                else if (channel.ElementType == typeof(Vector2))
                {
                    format = VertexElementFormat.Vector2;
                }
                else if (channel.ElementType == typeof(Vector3))
                {
                    format = VertexElementFormat.Vector3;
                }
                else if (channel.ElementType == typeof(Vector4))
                {
                    format = VertexElementFormat.Vector4;
                }
                else if (channel.ElementType == typeof(Color))
                {
                    format = VertexElementFormat.Color;
                }
                else if (channel.ElementType == typeof(Byte4))
                {
                    format = VertexElementFormat.Byte4;
                }
                else if (channel.ElementType == typeof(Short2))
                {
                    format = VertexElementFormat.Short2;
                }
                else if (channel.ElementType == typeof(Short4))
                {
                    format = VertexElementFormat.Short4;
                }
                else if (channel.ElementType == typeof(NormalizedShort2))
                {
                    format = VertexElementFormat.NormalizedShort2;
                }
                else if (channel.ElementType == typeof(NormalizedShort4))
                {
                    format = VertexElementFormat.NormalizedShort4;
                }
                else if (channel.ElementType == typeof(HalfVector2))
                {
                    format = VertexElementFormat.HalfVector2;
                }
                else if (channel.ElementType == typeof(HalfVector4))
                {
                    format = VertexElementFormat.HalfVector4;
                }
                else
                {
                    throw new InvalidContentException(string.Format("Unrecognized vertex content type: '{0}'", channel.ElementType));
                }

                // Try to determine the vertex usage
                if (!VertexChannelNames.TryDecodeUsage(channel.Name, out usage))
                {
                    throw new InvalidContentException(string.Format("Unknown vertex element usage for channel '{0}'", channel.Name));
                }

                // Try getting the usage index
                var usageIndex = VertexChannelNames.DecodeUsageIndex(channel.Name);

                result.VertexDeclaration.VertexElements.Add(new VertexElement(offset, format, usage, usageIndex));
                offset += format.GetSize();
                result.VertexDeclaration.VertexStride = offset;
            }
            return(offset);
        }