public void PostLoad() { if (PrimaryVertexData.Vertices.Count > 0) { VertexFormat = PrimaryVertexData.Vertices[0].Format; } }
private Mesh ImportMesh(geometry geom, mesh mesh, VertexDescriptor vertexFormat) { var collada = new ColladaMesh(); bool isSkinned = SkinnedMeshes.Contains(geom.id); collada.ImportFromCollada(mesh, vertexFormat, isSkinned, Options); var m = new Mesh(); m.VertexFormat = collada.InternalVertexType; m.Name = "Unnamed"; m.PrimaryVertexData = new VertexData(); m.PrimaryVertexData.Vertices = collada.ConsolidatedVertices; if (!Options.StripMetadata) { var components = m.VertexFormat.ComponentNames().Select(s => new GrannyString(s)).ToList(); m.PrimaryVertexData.VertexComponentNames = components; } else { m.PrimaryVertexData.VertexComponentNames = null; } m.PrimaryTopology = new TriTopology(); m.PrimaryTopology.Indices = collada.ConsolidatedIndices; m.PrimaryTopology.Groups = new List <TriTopologyGroup>(); var triGroup = new TriTopologyGroup(); triGroup.MaterialIndex = 0; triGroup.TriFirst = 0; triGroup.TriCount = collada.TriangleCount; m.PrimaryTopology.Groups.Add(triGroup); m.MaterialBindings = new List <MaterialBinding>(); m.MaterialBindings.Add(new MaterialBinding()); // m.BoneBindings; - TODO m.OriginalToConsolidatedVertexIndexMap = collada.OriginalToConsolidatedVertexIndexMap; var divModelType = FindDivModelType(mesh); if (divModelType != 0) { m.ModelType = divModelType; m.HasDefiniteModelType = true; } Utils.Info(String.Format("Imported {0} mesh ({1} tri groups, {2} tris)", (m.VertexFormat.HasBoneWeights ? "skinned" : "rigid"), m.PrimaryTopology.Groups.Count, collada.TriangleCount)); return(m); }
private Mesh ImportMesh(Root root, string name, geometry geom, mesh mesh, VertexDescriptor vertexFormat) { var m = ImportMesh(geom, mesh, vertexFormat); m.Name = name; root.VertexDatas.Add(m.PrimaryVertexData); root.TriTopologies.Add(m.PrimaryTopology); root.Meshes.Add(m); return(m); }
public void PostLoad() { if (PrimaryVertexData.Vertices.Count > 0) { VertexFormat = PrimaryVertexData.Vertices[0].Format; } if (HasDefiniteModelType == false) { ModelType = DivinityHelpers.DetermineModelFlags(this, out HasDefiniteModelType); } }
private VertexDescriptor FindVertexFormat(bool isSkinned) { var desc = new VertexDescriptor(); desc.HasPosition = true; if (isSkinned) { desc.HasBoneWeights = true; } foreach (var input in Mesh.vertices.input) { switch (input.semantic) { case "NORMAL": desc.NormalType = NormalType.Float3; break; case "TANGENT": desc.TangentType = NormalType.Float3; break; case "BINORMAL": desc.BinormalType = NormalType.Float3; break; } } foreach (var input in Inputs) { switch (input.semantic) { case "NORMAL": desc.NormalType = NormalType.Float3; break; case "TANGENT": desc.TangentType = NormalType.Float3; break; case "BINORMAL": desc.BinormalType = NormalType.Float3; break; case "TEXCOORD": desc.TextureCoordinateType = TextureCoordinateType.Float2; desc.TextureCoordinates++; break; case "COLOR": desc.ColorMapType = ColorMapType.Float4; desc.ColorMaps++; break; } } return(desc); }
public Root Import(string inputPath) { var collada = COLLADA.Load(inputPath); var root = new Root(); root.ArtToolInfo = ImportArtToolInfo(collada); if (!Options.StripMetadata) { root.ExporterInfo = ImportExporterInfo(collada); } root.FromFileName = inputPath; root.Skeletons = new List <Skeleton>(); root.VertexDatas = new List <VertexData>(); root.TriTopologies = new List <TriTopology>(); root.Meshes = new List <Mesh>(); root.Models = new List <Model>(); root.TrackGroups = new List <TrackGroup>(); root.Animations = new List <Animation>(); ColladaGeometries = new Dictionary <string, Mesh>(); SkinnedMeshes = new HashSet <string>(); var collGeometries = new List <geometry>(); var collSkins = new List <skin>(); var collAnimations = new List <animation>(); var rootBones = new List <RootBoneInfo>(); // Import skinning controllers after skeleton and geometry loading has finished, as // we reference both of them during skin import foreach (var item in collada.Items) { if (item is library_controllers) { var controllers = item as library_controllers; if (controllers.controller != null) { foreach (var controller in controllers.controller) { if (controller.Item is skin) { collSkins.Add(controller.Item as skin); SkinnedMeshes.Add((controller.Item as skin).source1.Substring(1)); } else { Utils.Warn(String.Format("Controller {0} is unsupported and will be ignored", controller.Item.GetType().Name)); } } } } else if (item is library_visual_scenes) { var scenes = item as library_visual_scenes; if (scenes.visual_scene != null) { foreach (var scene in scenes.visual_scene) { if (scene.node != null) { foreach (var node in scene.node) { FindRootBones(new List <node>(), node, rootBones); } } } } } else if (item is library_geometries) { var geometries = item as library_geometries; if (geometries.geometry != null) { foreach (var geometry in geometries.geometry) { if (geometry.Item is mesh) { collGeometries.Add(geometry); } else { Utils.Warn(String.Format("Geometry type {0} is unsupported and will be ignored", geometry.Item.GetType().Name)); } } } } else if (item is library_animations) { var animations = item as library_animations; if (animations.animation != null) { collAnimations.AddRange(animations.animation); } } else { Utils.Warn(String.Format("Library {0} is unsupported and will be ignored", item.GetType().Name)); } } foreach (var bone in rootBones) { var skeleton = Skeleton.FromCollada(bone.Bone); var rootTransform = NodeHelpers.GetTransformHierarchy(bone.Parents); skeleton.TransformRoots(rootTransform.Inverted()); root.Skeletons.Add(skeleton); } foreach (var geometry in collGeometries) { VertexDescriptor vertexFormat = null; // Use the override vertex format, if one was specified Options.VertexFormats.TryGetValue(geometry.name, out vertexFormat); var mesh = ImportMesh(root, geometry.name, geometry, geometry.Item as mesh, vertexFormat); ColladaGeometries.Add(geometry.id, mesh); } // Import skinning controllers after skeleton and geometry loading has finished, as // we reference both of them during skin import if (rootBones.Count > 0) { foreach (var skin in collSkins) { ImportSkin(root, skin); } } if (collAnimations.Count > 0) { ImportAnimations(collAnimations, root, root.Skeletons.FirstOrDefault()); } var rootModel = new Model(); rootModel.Name = "Unnamed"; // TODO if (root.Skeletons.Count > 0) { rootModel.Skeleton = root.Skeletons[0]; rootModel.Name = rootModel.Skeleton.Bones[0].Name; } rootModel.InitialPlacement = new Transform(); rootModel.MeshBindings = new List <MeshBinding>(); foreach (var mesh in root.Meshes) { var binding = new MeshBinding(); binding.Mesh = mesh; rootModel.MeshBindings.Add(binding); } root.Models.Add(rootModel); // TODO: make this an option! if (root.Skeletons.Count > 0) { root.Skeletons[0].UpdateWorldTransforms(); } root.ZUp = ZUp; root.PostLoad(GR2.Header.DefaultTag); this.UpdateUserDefinedProperties(root); return(root); }
public VertexDescriptor ConstructDescriptor(MemberDefinition memberDefn, StructDefinition defn, object parent) { var desc = new VertexDescriptor(); foreach (var member in defn.Members) { switch (member.Name) { case "Position": if (member.Type != MemberType.Real32 || member.ArraySize != 3) { throw new Exception("Vertex position must be a Vector3"); } desc.HasPosition = true; break; case "BoneWeights": if (member.Type != MemberType.NormalUInt8) { throw new Exception("Bone weight must be a NormalUInt8"); } if (member.ArraySize != 2 && member.ArraySize != 4) { throw new Exception($"Unsupported bone influence count: {member.ArraySize}"); } desc.HasBoneWeights = true; desc.NumBoneInfluences = (int)member.ArraySize; break; case "BoneIndices": if (member.Type != MemberType.UInt8) { throw new Exception("Bone index must be an UInt8"); } break; case "Normal": if (member.Type == MemberType.Real32 && member.ArraySize == 3) { desc.NormalType = NormalType.Float3; } else if (member.Type == MemberType.Real16 && member.ArraySize == 4) { desc.NormalType = NormalType.Half4; } else { throw new Exception($"Unsupported normal format: {member.Type}, {member.ArraySize}"); } break; case "QTangent": if (member.Type == MemberType.BinormalInt16 && member.ArraySize == 4) { desc.NormalType = NormalType.QTangent; desc.TangentType = NormalType.QTangent; desc.BinormalType = NormalType.QTangent; } else { throw new Exception($"Unsupported QTangent format: {member.Type}, {member.ArraySize}"); } break; case "Tangent": if (member.Type == MemberType.Real32 && member.ArraySize == 3) { desc.TangentType = NormalType.Float3; } else if (member.Type == MemberType.Real16 && member.ArraySize == 4) { desc.NormalType = NormalType.Half4; } else { throw new Exception($"Unsupported tangent format: {member.Type}, {member.ArraySize}"); } break; case "Binormal": if (member.Type == MemberType.Real32 && member.ArraySize == 3) { desc.BinormalType = NormalType.Float3; } else if (member.Type == MemberType.Real16 && member.ArraySize == 4) { desc.NormalType = NormalType.Half4; } else { throw new Exception($"Unsupported binormal format: {member.Type}, {member.ArraySize}"); } break; case "DiffuseColor0": case "DiffuseColor1": desc.ColorMaps++; if (member.Type == MemberType.Real32 && member.ArraySize == 4) { desc.ColorMapType = ColorMapType.Float4; } else if (member.Type == MemberType.NormalUInt8 && member.ArraySize == 4) { desc.ColorMapType = ColorMapType.Byte4; } //Some Granny2 model formats report their color maps as UInt8 type instead of NormalUInt8, causing it to fail checks. else if (member.Type == MemberType.UInt8 && member.ArraySize == 4) { desc.ColorMapType = ColorMapType.Byte4; } else { throw new Exception($"Unsupported color map type: {member.Type}, {member.ArraySize}"); } break; case "TextureCoordinates0": case "TextureCoordinates1": case "TextureCoordinates2": case "TextureCoordinates3": desc.TextureCoordinates++; if (member.Type == MemberType.Real32 && member.ArraySize == 2) { desc.TextureCoordinateType = TextureCoordinateType.Float2; } else if (member.Type == MemberType.Real16 && member.ArraySize == 2) { desc.TextureCoordinateType = TextureCoordinateType.Half2; } else { throw new Exception($"Unsupported texture coordinate format: {member.Type}, {member.ArraySize}"); } break; default: throw new Exception($"Unknown vertex property: {member.Name}"); } } return(desc); }
public VertexDescriptor ConstructDescriptor(MemberDefinition memberDefn, StructDefinition defn, object parent) { var desc = new VertexDescriptor(); foreach (var member in defn.Members) { switch (member.Name) { case "Position": if (member.Type != MemberType.Real32 || member.ArraySize != 3) { throw new Exception("Vertex position must be a Vector3"); } desc.HasPosition = true; break; case "BoneWeights": if (member.Type != MemberType.NormalUInt8) { throw new Exception("Bone weight must be a NormalUInt8"); } if (member.ArraySize != 2 && member.ArraySize != 4) { throw new Exception("Unsupported bone influence count"); } desc.HasBoneWeights = true; desc.NumBoneInfluences = (int)member.ArraySize; break; case "BoneIndices": if (member.Type != MemberType.UInt8) { throw new Exception("Bone index must be an UInt8"); } break; case "Normal": if (member.Type == MemberType.Real32 && member.ArraySize == 3) { desc.NormalType = NormalType.Float3; } else if (member.Type == MemberType.Real16 && member.ArraySize == 4) { desc.NormalType = NormalType.Half4; } else if (member.Type == MemberType.BinormalInt16 && member.ArraySize == 4) { desc.NormalType = NormalType.Short4; } else { throw new Exception("Unsupported vertex normal format"); } break; case "QTangent": // TODO - different format? case "Tangent": if (member.Type == MemberType.Real32 && member.ArraySize == 3) { desc.TangentType = NormalType.Float3; } else if (member.Type == MemberType.Real16 && member.ArraySize == 4) { desc.NormalType = NormalType.Half4; } else if (member.Type == MemberType.BinormalInt16 && member.ArraySize == 4) { desc.NormalType = NormalType.Short4; } else { throw new Exception("Unsupported vertex tangent format"); } break; case "Binormal": if (member.Type == MemberType.Real32 && member.ArraySize == 3) { desc.BinormalType = NormalType.Float3; } else if (member.Type == MemberType.Real16 && member.ArraySize == 4) { desc.NormalType = NormalType.Half4; } else if (member.Type == MemberType.BinormalInt16 && member.ArraySize == 4) { desc.NormalType = NormalType.Short4; } else { throw new Exception("Unsupported vertex binormal format"); } break; case "DiffuseColor0": desc.DiffuseColors = 1; if (member.Type == MemberType.Real32 && member.ArraySize == 4) { desc.DiffuseType = DiffuseColorType.Float4; } else if (member.Type == MemberType.NormalUInt8 && member.ArraySize == 4) { desc.DiffuseType = DiffuseColorType.Byte4; } else { throw new Exception("Unsupported vertex diffuse color type"); } break; case "TextureCoordinates0": desc.TextureCoordinates = 1; if (member.Type == MemberType.Real32 && member.ArraySize == 2) { desc.TextureCoordinateType = TextureCoordinateType.Float2; } else if (member.Type == MemberType.Real16 && member.ArraySize == 2) { desc.TextureCoordinateType = TextureCoordinateType.Half2; } else { throw new Exception("Unsupported vertex binormal format"); } break; case "TextureCoordinates1": desc.TextureCoordinates = 2; break; default: throw new Exception($"Unknown vertex property: {member.Name}"); } } return(desc); }
public void ImportFromCollada(mesh mesh, VertexDescriptor vertexFormat, bool isSkinned, ExporterOptions options) { Options = options; Mesh = mesh; ImportSources(); ImportFaces(); if (vertexFormat == null) { vertexFormat = FindVertexFormat(isSkinned); } InputVertexType = vertexFormat; OutputVertexType = new VertexDescriptor { HasPosition = InputVertexType.HasPosition, HasBoneWeights = InputVertexType.HasBoneWeights, NumBoneInfluences = InputVertexType.NumBoneInfluences, NormalType = InputVertexType.NormalType, TangentType = InputVertexType.TangentType, BinormalType = InputVertexType.BinormalType, ColorMapType = InputVertexType.ColorMapType, ColorMaps = InputVertexType.ColorMaps, TextureCoordinateType = InputVertexType.TextureCoordinateType, TextureCoordinates = InputVertexType.TextureCoordinates }; ImportVertices(); // TODO: This should be done before deduplication! // TODO: Move this to somewhere else ... ? if (!HasNormals || Options.RecalculateNormals) { if (!HasNormals) { Utils.Info(String.Format("Channel 'NORMAL' not found, will rebuild vertex normals after import.")); } HasNormals = true; OutputVertexType.NormalType = NormalType.Float3; computeNormals(); } ImportColors(); ImportUVs(); if (UVInputIndices.Count() > 0 || ColorInputIndices.Count() > 0 || NormalsInputIndex != -1 || TangentsInputIndex != -1 || BinormalsInputIndex != -1) { var outVertexIndices = new Dictionary <int[], int>(new VertexIndexComparer()); ConsolidatedIndices = new List <int>(TriangleCount * 3); ConsolidatedVertices = new List <Vertex>(Vertices.Count); OriginalToConsolidatedVertexIndexMap = new Dictionary <int, List <int> >(); for (var vert = 0; vert < TriangleCount * 3; vert++) { var index = new int[InputOffsetCount]; for (var i = 0; i < InputOffsetCount; i++) { index[i] = Indices[vert * InputOffsetCount + i]; } int consolidatedIndex; if (!outVertexIndices.TryGetValue(index, out consolidatedIndex)) { var vertexIndex = index[VertexInputIndex]; consolidatedIndex = ConsolidatedVertices.Count; Vertex vertex = Vertices[vertexIndex].Clone(); if (NormalsInputIndex != -1) { vertex.Normal = Normals[index[NormalsInputIndex]]; } if (TangentsInputIndex != -1) { vertex.Tangent = Tangents[index[TangentsInputIndex]]; } if (BinormalsInputIndex != -1) { vertex.Binormal = Binormals[index[BinormalsInputIndex]]; } for (int uv = 0; uv < UVInputIndices.Count(); uv++) { vertex.SetUV(uv, UVs[uv][index[UVInputIndices[uv]]]); } for (int color = 0; color < ColorInputIndices.Count(); color++) { vertex.SetColor(color, Colors[color][index[ColorInputIndices[color]]]); } outVertexIndices.Add(index, consolidatedIndex); ConsolidatedVertices.Add(vertex); List <int> mappedIndices = null; if (!OriginalToConsolidatedVertexIndexMap.TryGetValue(vertexIndex, out mappedIndices)) { mappedIndices = new List <int>(); OriginalToConsolidatedVertexIndexMap.Add(vertexIndex, mappedIndices); } mappedIndices.Add(consolidatedIndex); } ConsolidatedIndices.Add(consolidatedIndex); } Utils.Info(String.Format("Merged {0} vertices into {1} output vertices", Vertices.Count, ConsolidatedVertices.Count)); } else { Utils.Info(String.Format("Mesh has no separate normals, colors or UV map, vertex consolidation step skipped.")); ConsolidatedVertices = Vertices; ConsolidatedIndices = new List <int>(TriangleCount * 3); for (var vert = 0; vert < TriangleCount * 3; vert++) { ConsolidatedIndices.Add(VertexIndex(vert)); } OriginalToConsolidatedVertexIndexMap = new Dictionary <int, List <int> >(); for (var i = 0; i < Vertices.Count; i++) { OriginalToConsolidatedVertexIndexMap.Add(i, new List <int> { i }); } } if ((InputVertexType.TangentType == NormalType.None || InputVertexType.BinormalType == NormalType.None) && ((!HasTangents && UVs.Count > 0) || Options.RecalculateTangents)) { if (!HasTangents) { Utils.Info(String.Format("Channel 'TANGENT'/'BINROMAL' not found, will rebuild vertex tangents after import.")); } OutputVertexType.TangentType = NormalType.Float3; OutputVertexType.BinormalType = NormalType.Float3; HasTangents = true; computeTangents(); } // Use optimized tangent, texture map and color map format when exporting for D:OS 2 if ((Options.ModelInfoFormat == DivinityModelInfoFormat.LSMv0 || Options.ModelInfoFormat == DivinityModelInfoFormat.LSMv1) && HasNormals && HasTangents) { OutputVertexType.NormalType = NormalType.QTangent; OutputVertexType.TangentType = NormalType.QTangent; OutputVertexType.BinormalType = NormalType.QTangent; if (OutputVertexType.TextureCoordinateType == TextureCoordinateType.Float2) { OutputVertexType.TextureCoordinateType = TextureCoordinateType.Half2; } if (OutputVertexType.ColorMapType == ColorMapType.Float4) { OutputVertexType.ColorMapType = ColorMapType.Byte4; } } }
public static List <DivinityFormatDesc> FromVertexFormat(VertexDescriptor format) { var formats = new List <DivinityFormatDesc>(); if (format.HasPosition) { formats.Add(Make(DivinityVertexUsage.Position, DivinityVertexAttributeFormat.Real32, 3)); } if (format.HasBoneWeights) { formats.Add(Make(DivinityVertexUsage.BoneWeights, DivinityVertexAttributeFormat.NormalUInt8, (byte)format.NumBoneInfluences)); formats.Add(Make(DivinityVertexUsage.BoneIndices, DivinityVertexAttributeFormat.UInt8, (byte)format.NumBoneInfluences)); } if (format.NormalType != NormalType.None) { if (format.NormalType == NormalType.QTangent) { formats.Add(Make(DivinityVertexUsage.QTangent, DivinityVertexAttributeFormat.BinormalInt16, 4)); } else if (format.NormalType == NormalType.Float3) { formats.Add(Make(DivinityVertexUsage.Normal, DivinityVertexAttributeFormat.Real32, 3)); if (format.TangentType == NormalType.Float3) { formats.Add(Make(DivinityVertexUsage.Tangent, DivinityVertexAttributeFormat.Real32, 3)); } if (format.BinormalType == NormalType.Float3) { formats.Add(Make(DivinityVertexUsage.Binormal, DivinityVertexAttributeFormat.Real32, 3)); } } else { throw new InvalidOperationException($"Normal format not supported in LSM: {format.NormalType}"); } } if (format.ColorMapType != ColorMapType.None) { if (format.ColorMapType == ColorMapType.Byte4) { for (int i = 0; i < format.ColorMaps; i++) { formats.Add(Make(DivinityVertexUsage.Color, DivinityVertexAttributeFormat.NormalUInt8, 4, (byte)i)); } } else if (format.ColorMapType == ColorMapType.Float4) { for (int i = 0; i < format.ColorMaps; i++) { formats.Add(Make(DivinityVertexUsage.Color, DivinityVertexAttributeFormat.Real32, 4, (byte)i)); } } else { throw new InvalidOperationException($"Color format not supported in LSM: {format.ColorMapType}"); } } if (format.TextureCoordinateType != TextureCoordinateType.None) { if (format.TextureCoordinateType == TextureCoordinateType.Half2) { for (int i = 0; i < format.TextureCoordinates; i++) { formats.Add(Make(DivinityVertexUsage.TexCoord, DivinityVertexAttributeFormat.Real16, 2, (byte)i)); } } else if (format.TextureCoordinateType == TextureCoordinateType.Float2) { for (int i = 0; i < format.TextureCoordinates; i++) { formats.Add(Make(DivinityVertexUsage.TexCoord, DivinityVertexAttributeFormat.Real32, 2, (byte)i)); } } else { throw new InvalidOperationException($"UV format not supported in LSM: {format.TextureCoordinateType}"); } } return(formats); }