/// <summary> /// Reads skinning data /// </summary> /// <param name="description">Description</param> /// <param name="modelContent">Model content</param> /// <param name="meshName">Mesh name</param> /// <param name="bindShapeMatrix">Resulting bind shape matrix</param> /// <param name="weights">Resulting weights</param> /// <param name="jointNames">Resulting joints</param> /// <returns>Returns true if the model has skinnging data</returns> private static bool ReadSkinningData(DrawingDataDescription description, ModelContent modelContent, string meshName, out Matrix bindShapeMatrix, out Weight[] weights, out string[] jointNames) { bindShapeMatrix = Matrix.Identity; weights = null; jointNames = null; if (description.LoadAnimation && modelContent.Controllers != null && modelContent.SkinningInfo != null) { var cInfo = modelContent.Controllers.GetControllerForMesh(meshName); if (cInfo != null) { //Apply shape matrix if controller exists but we are not loading animation info bindShapeMatrix = cInfo.BindShapeMatrix; weights = cInfo.Weights; //Find skeleton for controller var sInfo = modelContent.SkinningInfo[cInfo.Armature]; jointNames = sInfo.Skeleton.GetJointNames(); return(true); } } return(false); }
/// <summary> /// Process the vertex data /// </summary> /// <param name="description">Decription</param> /// <param name="geometry">Geometry</param> /// <param name="vertexType">Vertext type</param> /// <param name="vertices">Resulting vertices</param> /// <param name="indices">Resulting indices</param> private static void ProcessVertexData(DrawingDataDescription description, SubMeshContent geometry, VertexTypes vertexType, out VertexData[] vertices, out uint[] indices) { if (VertexData.IsTangent(vertexType)) { geometry.ComputeTangents(); } if (!description.Constraint.HasValue) { vertices = geometry.Vertices; indices = geometry.Indices; return; } if (geometry.Indices?.Length > 0) { ComputeConstraintIndices( description.Constraint.Value, geometry.Vertices, geometry.Indices, out vertices, out indices); } else { ComputeConstraintVertices( description.Constraint.Value, geometry.Vertices, out vertices); indices = new uint[] { }; } }
/// <summary> /// Get vertex type from geometry /// </summary> /// <param name="description">Description</param> /// <param name="materials">Material dictionary</param> /// <param name="vertexType">Vertex type</param> /// <param name="isSkinned">Sets wether the current geometry has skinning data or not</param> /// <param name="material">Material name</param> /// <returns>Returns the vertex type</returns> private static VertexTypes GetVertexType(DrawingDataDescription description, MaterialDictionary materials, VertexTypes vertexType, bool isSkinned, string material) { var res = vertexType; if (isSkinned) { //Get skinned equivalent res = VertexData.GetSkinnedEquivalent(res); } if (!description.LoadNormalMaps) { return(res); } if (VertexData.IsTextured(res) && !VertexData.IsTangent(res)) { var meshMaterial = materials[material]; if (meshMaterial?.NormalMap != null) { //Get tangent equivalent res = VertexData.GetTangentEquivalent(res); } } return(res); }
/// <summary> /// Model initialization /// </summary> /// <param name="game">Game</param> /// <param name="bufferManager">Buffer manager</param> /// <param name="modelContent">Model content</param> /// <param name="description">Data description</param> /// <returns>Returns the generated drawing data objects</returns> public static DrawingData Build(Game game, BufferManager bufferManager, ModelContent modelContent, DrawingDataDescription description) { DrawingData res = new DrawingData(bufferManager); //Animation if (description.LoadAnimation) { InitializeSkinningData(ref res, modelContent); } //Images InitializeTextures(ref res, game, modelContent, description.TextureCount); //Materials InitializeMaterials(ref res, modelContent); //Skins & Meshes InitializeGeometry(ref res, modelContent, description); //Update meshes into device InitializeMeshes(ref res, bufferManager, description.Instanced ? description.Instances : 0); //Lights InitializeLights(ref res, modelContent); return(res); }
/// <summary> /// Initilize geometry /// </summary> /// <param name="drw">Drawing data</param> /// <param name="modelContent">Model content</param> /// <param name="description">Description</param> private static void InitializeGeometry(ref DrawingData drw, ModelContent modelContent, DrawingDataDescription description) { List <Triangle> volumeMesh = new List <Triangle>(); foreach (string meshName in modelContent.Geometry.Keys) { //Get skinning data var isSkinned = ReadSkinningData( description, modelContent, meshName, out var bindShapeMatrix, out var weights, out var jointNames); //Process the mesh geometry material by material var dictGeometry = modelContent.Geometry[meshName]; foreach (string material in dictGeometry.Keys) { var geometry = dictGeometry[material]; if (geometry.IsVolume) { //If volume, store position only volumeMesh.AddRange(geometry.GetTriangles()); } else { //Get vertex type var vertexType = GetVertexType(description, drw.Materials, geometry.VertexType, isSkinned, material); //Process the vertex data ProcessVertexData( description, geometry, vertexType, out var vertices, out var indices); for (int i = 0; i < vertices.Length; i++) { vertices[i] = vertices[i].Transform(bindShapeMatrix); } //Convert the vertex data to final mesh data var vertexList = VertexData.Convert( vertexType, vertices, weights, jointNames); if (vertexList.Any()) { //Create and store the mesh into the drawing data Mesh nMesh = new Mesh( meshName, geometry.Topology, vertexList.ToArray(), indices); drw.Meshes.Add(meshName, geometry.Material, nMesh); } } } } drw.VolumeMesh = volumeMesh.ToArray(); }
/// <summary> /// Base model /// </summary> /// <param name="scene">Scene</param> /// <param name="description">Object description</param> protected BaseModel(Scene scene, BaseModelDescription description) : base(scene, description) { var desc = new DrawingDataDescription() { Instanced = description.Instanced, Instances = description.Instances, LoadAnimation = description.LoadAnimation, LoadNormalMaps = description.LoadNormalMaps, TextureCount = this.TextureCount, DynamicBuffers = description.Dynamic, }; IEnumerable <ModelContent> geo; if (!string.IsNullOrEmpty(description.Content.ModelContentFilename)) { string contentFile = Path.Combine(description.Content.ContentFolder, description.Content.ModelContentFilename); var contentDesc = Helper.DeserializeFromFile <ModelContentDescription>(contentFile); var loader = contentDesc.GetLoader(); geo = loader.Load(description.Content.ContentFolder, contentDesc); } else if (description.Content.ModelContentDescription != null) { var loader = description.Content.ModelContentDescription.GetLoader(); geo = loader.Load(description.Content.ContentFolder, description.Content.ModelContentDescription); } else if (description.Content.ModelContent != null) { geo = new[] { description.Content.ModelContent }; } else { throw new EngineException("No geometry found in description."); } if (geo.Count() == 1) { var iGeo = geo.First(); if (description.Optimize) { iGeo.Optimize(); } var drawable = DrawingData.Build(this.Game, this.BufferManager, iGeo, desc); this.meshesByLOD.Add(LevelOfDetail.High, drawable); } else { var content = new LevelOfDetailModelContent(geo, description.Optimize); foreach (var lod in content.Keys) { if (this.defaultLevelOfDetail == LevelOfDetail.None) { this.defaultLevelOfDetail = lod; } var drawable = DrawingData.Build(this.Game, this.BufferManager, content[lod], desc); this.meshesByLOD.Add(lod, drawable); } } this.UseAnisotropicFiltering = description.UseAnisotropicFiltering; }