private void AddTangentFrames(MeshContent mesh, ModelDescription modelDescription, MeshDescription meshDescription) { string textureCoordinateChannelName = VertexChannelNames.TextureCoordinate(0); string tangentChannelName = VertexChannelNames.Tangent(0); string binormalChannelName = VertexChannelNames.Binormal(0); bool normalsCalculated = false; for (int i = 0; i < mesh.Geometry.Count; i++) { var geometry = mesh.Geometry[i]; // Check whether tangent frames are required. var submeshDescription = (meshDescription != null) ? meshDescription.GetSubmeshDescription(i) : null; if (submeshDescription != null && submeshDescription.GenerateTangentFrames || meshDescription != null && meshDescription.GenerateTangentFrames || modelDescription != null && modelDescription.GenerateTangentFrames) { // Ensure that normals are set. if (!normalsCalculated) { CalculateNormals(mesh, false); normalsCalculated = true; } var channels = geometry.Vertices.Channels; bool tangentsMissing = !channels.Contains(tangentChannelName); bool binormalsMissing = !channels.Contains(binormalChannelName); if (tangentsMissing || binormalsMissing) { // Texture coordinates are required for calculating tangent frames. if (!channels.Contains(textureCoordinateChannelName)) { _context.Logger.LogWarning( null, mesh.Identity, "Texture coordinates missing in mesh '{0}', submesh {1}. Texture coordinates are required " + "for calculating tangent frames.", mesh.Name, i); channels.Add <Vector2>(textureCoordinateChannelName, null); } CalculateTangentFrames( geometry, textureCoordinateChannelName, tangentsMissing ? tangentChannelName : null, binormalsMissing ? binormalChannelName : null); } } } }
public static ModelDescription Load(string sourceFileName, ContentPipelineContext context, bool createIfMissing) { if (sourceFileName == null) { throw new ArgumentNullException("sourceFileName"); } if (sourceFileName.Length == 0) { throw new ArgumentException("File name must not be empty.", "sourceFileName"); } if (context == null) { throw new ArgumentNullException("context"); } string fileName = Path.ChangeExtension(sourceFileName, "drmdl"); if (!File.Exists(fileName)) { // Also try with extension xml, which was used before drmdl. fileName = Path.ChangeExtension(sourceFileName, "xml"); if (!IsModelDescriptionFile(fileName)) { fileName = Path.ChangeExtension(sourceFileName, "drmdl"); if (!createIfMissing) { context.Logger.LogImportantMessage( "The model description file \"{0}\" is missing. Using default settings.", Path.GetFileName(fileName)); return(null); } // Create default model description file. try { using (var stream = File.CreateText(fileName)) { stream.Write(Properties.Resources.DefaultModelDescription, Path.GetFileName(sourceFileName)); } } catch (Exception exception) { context.Logger.LogImportantMessage( "Automatic creation of model description \"{0}\" failed. Using default settings.\nException: {1}", fileName, exception.ToString()); return(null); } } } context.AddDependency(fileName); var modelDescription = new ModelDescription { Identity = new ContentIdentity(fileName) }; XDocument document; try { document = XDocument.Load(fileName, LoadOptions.SetLineInfo); } catch (Exception exception) { string message = string.Format(CultureInfo.InvariantCulture, "Could not load '{0}': {1}", fileName, exception.Message); throw new InvalidContentException(message, modelDescription.Identity); } var modelElement = document.Root; if (modelElement == null || modelElement.Name != "Model") { string message = string.Format(CultureInfo.InvariantCulture, "Root element \"<Model>\" is missing in XML."); throw new InvalidContentException(message, modelDescription.Identity); } // Model attributes. modelDescription.Name = (string)modelElement.Attribute("Name") ?? Path.GetFileNameWithoutExtension(fileName); modelDescription.FileName = (string)modelElement.Attribute("File") ?? (string)modelElement.Attribute("FileName"); modelDescription.Importer = (string)modelElement.Attribute("Importer"); modelDescription.RotationX = (float?)modelElement.Attribute("RotationX") ?? 0.0f; modelDescription.RotationY = (float?)modelElement.Attribute("RotationY") ?? 0.0f; modelDescription.RotationZ = (float?)modelElement.Attribute("RotationZ") ?? 0.0f; modelDescription.Scale = (float?)modelElement.Attribute("Scale") ?? 1.0f; modelDescription.GenerateTangentFrames = (bool?)modelElement.Attribute("GenerateTangentFrames") ?? false; modelDescription.SwapWindingOrder = (bool?)modelElement.Attribute("SwapWindingOrder") ?? false; modelDescription.PremultiplyVertexColors = (bool?)modelElement.Attribute("PremultiplyVertexColors") ?? true; modelDescription.MaxDistance = (float?)modelElement.Attribute("MaxDistance") ?? 0.0f; var aabbMinimumAttribute = modelElement.Attribute("AabbMinimum"); var aabbMaximumAttribute = modelElement.Attribute("AabbMaximum"); if (aabbMinimumAttribute != null && aabbMaximumAttribute != null) { modelDescription.AabbEnabled = true; modelDescription.AabbMinimum = aabbMinimumAttribute.ToVector3(Vector3.Zero, modelDescription.Identity); modelDescription.AabbMaximum = aabbMaximumAttribute.ToVector3(Vector3.One, modelDescription.Identity); } // Mesh elements. modelDescription.Meshes = new List <MeshDescription>(); foreach (var meshElement in modelElement.Elements("Mesh")) { var meshDescription = new MeshDescription(); meshDescription.Name = (string)meshElement.Attribute("Name") ?? string.Empty; meshDescription.GenerateTangentFrames = (bool?)meshElement.Attribute("GenerateTangentFrames") ?? modelDescription.GenerateTangentFrames; meshDescription.MaxDistance = (float?)meshElement.Attribute("MaxDistance") ?? modelDescription.MaxDistance; meshDescription.LodDistance = (float?)meshElement.Attribute("LodDistance") ?? 0.0f; meshDescription.Submeshes = new List <SubmeshDescription>(); foreach (var submeshElement in meshElement.Elements("Submesh")) { var submeshDescription = new SubmeshDescription(); submeshDescription.GenerateTangentFrames = (bool?)meshElement.Attribute("GenerateTangentFrames") ?? meshDescription.GenerateTangentFrames; submeshDescription.Material = (string)submeshElement.Attribute("Material"); meshDescription.Submeshes.Add(submeshDescription); } modelDescription.Meshes.Add(meshDescription); } // Animations element. var animationsElement = modelElement.Element("Animations"); if (animationsElement != null) { var animationDescription = new AnimationDescription(); animationDescription.MergeFiles = (string)animationsElement.Attribute("MergeFiles"); animationDescription.Splits = AnimationSplitter.ParseAnimationSplitDefinitions(animationsElement, modelDescription.Identity, context); animationDescription.ScaleCompression = (float?)animationsElement.Attribute("ScaleCompression") ?? -1; animationDescription.RotationCompression = (float?)animationsElement.Attribute("RotationCompression") ?? -1; animationDescription.TranslationCompression = (float?)animationsElement.Attribute("TranslationCompression") ?? -1; animationDescription.AddLoopFrame = (bool?)animationsElement.Attribute("AddLoopFrame"); modelDescription.Animation = animationDescription; } return(modelDescription); }