public static Description ( |
||
type | ||
return |
public bool IsSkinned() { // Check if we have both the BoneWeights and BoneIndices vertex components. bool hasWeights = false, hasIndices = false; // If we have vertices, check the vertex prototype, as VertexComponentNames is unreliable. if (PrimaryVertexData.Vertices.Count > 0) { var desc = Vertex.Description(PrimaryVertexData.Vertices[0].GetType()); hasWeights = desc.BoneWeights; hasIndices = desc.BoneIndices; } else { // Otherwise try to figure out the components from VertexComponentNames foreach (var component in PrimaryVertexData.VertexComponentNames) { if (component.String == "BoneWeights") { hasWeights = true; } else if (component.String == "BoneIndices") { hasIndices = true; } } } return(hasWeights && hasIndices); }
private void DetermineInputsFromVertex(Vertex vertex) { var desc = Vertex.Description(vertex.GetType()); if (!desc.Position) { throw new NotImplementedException("Cannot import vertices without position"); } // Vertex positions var positions = ExportedMesh.PrimaryVertexData.MakeColladaPositions(ExportedMesh.Name); AddInput(positions, "POSITION", "VERTEX"); // Normals if (desc.Normal && Options.ExportNormals) { var normals = ExportedMesh.PrimaryVertexData.MakeColladaNormals(ExportedMesh.Name); AddInput(normals, "NORMAL"); } // Tangents if (desc.Tangent && Options.ExportTangents) { var normals = ExportedMesh.PrimaryVertexData.MakeColladaTangents(ExportedMesh.Name); AddInput(normals, "TANGENT"); } // Binormals if (desc.Binormal && Options.ExportTangents) { var normals = ExportedMesh.PrimaryVertexData.MakeColladaBinormals(ExportedMesh.Name); AddInput(normals, "BINORMAL"); } // Texture coordinates if (Options.ExportUVs) { for (var uvIndex = 0; uvIndex < desc.TextureCoordinates; uvIndex++) { var uvs = ExportedMesh.PrimaryVertexData.MakeColladaUVs(ExportedMesh.Name, uvIndex, Options.FlipUVs); AddInput(uvs, null, "TEXCOORD", (ulong)uvIndex); } } // Vertex colors if (Options.ExportColors) { for (var colorIndex = 0; colorIndex < desc.DiffuseColors; colorIndex++) { var colors = ExportedMesh.PrimaryVertexData.MakeColladaColors(ExportedMesh.Name, colorIndex); AddInput(colors, null, "COLOR", (ulong)colorIndex); } } // BoneWeights and BoneIndices are handled in ExportSkin() // TODO: DiffuseColor0 is not exported at the moment. }
public static Mesh ImportFromCollada(mesh mesh, string vertexFormat, bool rebuildNormals = false, bool rebuildTangents = false) { var collada = new ColladaMesh(); collada.ImportFromCollada(mesh, vertexFormat, rebuildNormals, rebuildTangents); var m = new Mesh(); m.VertexFormat = VertexFormatRegistry.Resolve(vertexFormat); m.Name = "Unnamed"; m.PrimaryVertexData = new VertexData(); var components = new List <GrannyString>(); components.Add(new GrannyString("Position")); var vertexDesc = Vertex.Description(m.VertexFormat); if (vertexDesc.BoneWeights) { components.Add(new GrannyString("BoneWeights")); components.Add(new GrannyString("BoneIndices")); } components.Add(new GrannyString("Normal")); components.Add(new GrannyString("Tangent")); components.Add(new GrannyString("Binormal")); components.Add(new GrannyString("MaxChannel_1")); m.PrimaryVertexData.VertexComponentNames = components; m.PrimaryVertexData.Vertices = collada.ConsolidatedVertices; 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; Utils.Info(String.Format("Imported {0} mesh ({1} tri groups, {2} tris)", (vertexDesc.BoneWeights ? "skinned" : "rigid"), m.PrimaryTopology.Groups.Count, collada.TriangleCount)); return(m); }
public static DivinityModelType DetermineModelType(Root root) { // Check if one of the meshes already has a UserDefinedProperties attribute. if (root.Meshes != null) { foreach (var mesh in root.Meshes) { if (mesh.ExtendedData != null && mesh.ExtendedData.UserDefinedProperties != null && mesh.ExtendedData.UserDefinedProperties.Length > 0) { return(UserDefinedPropertiesToModelType(mesh.ExtendedData.UserDefinedProperties)); } } } // Check if one of the bones already has a UserDefinedProperties attribute. if (root.Skeletons != null) { foreach (var skeleton in root.Skeletons) { if (skeleton.Bones != null) { foreach (var bone in skeleton.Bones) { if (bone.ExtendedData != null && bone.ExtendedData.UserDefinedProperties != null && bone.ExtendedData.UserDefinedProperties.Length > 0) { return(UserDefinedPropertiesToModelType(bone.ExtendedData.UserDefinedProperties)); } } } } } // Check if any of the meshes has a rigid vertex format if (root.Meshes != null) { foreach (var mesh in root.Meshes) { var isSkinned = Vertex.Description(mesh.VertexFormat).BoneWeights; if (!isSkinned) { return(DivinityModelType.Rigid); } } } return(DivinityModelType.Normal); }
public SectionType SelectSection(MemberDefinition member, Type type, object obj) { var vertices = obj as System.Collections.IList; if (vertices == null || vertices.Count == 0) { return(SectionType.RigidVertex); } if (Vertex.Description(vertices[0].GetType()).BoneWeights) { return(SectionType.DeformableVertex); } else { return(SectionType.RigidVertex); } }
public void Deduplicate(List <Vertex> vertices) { var positions = new Dictionary <Vector3, int>(new VertexPositionComparer()); for (var i = 0; i < vertices.Count; i++) { int mappedIndex; if (!positions.TryGetValue(vertices[i].Position, out mappedIndex)) { mappedIndex = positions.Count; positions.Add(vertices[i].Position, mappedIndex); DeduplicatedPositions.Add(vertices[i]); } VertexDeduplicationMap.Add(i, mappedIndex); } var numUvs = Vertex.Description(vertices[0].GetType()).TextureCoordinates; for (var uv = 0; uv < numUvs; uv++) { var uvMap = new Dictionary <int, int>(); var deduplicatedUvs = new List <Vector2>(); UVDeduplicationMaps.Add(uvMap); DeduplicatedUVs.Add(deduplicatedUvs); var uvs = new Dictionary <Vector2, int>(new VertexUVComparer()); for (var i = 0; i < vertices.Count; i++) { int mappedIndex; if (!uvs.TryGetValue(vertices[i].GetTextureCoordinates(uv), out mappedIndex)) { mappedIndex = uvs.Count; uvs.Add(vertices[i].GetTextureCoordinates(uv), mappedIndex); deduplicatedUvs.Add(vertices[i].GetTextureCoordinates(uv)); } uvMap.Add(i, mappedIndex); } } }
public void MakeIdentityMapping(List <Vertex> vertices) { for (var i = 0; i < vertices.Count; i++) { DeduplicatedPositions.Add(vertices[i]); VertexDeduplicationMap.Add(i, i); } var numUvs = Vertex.Description(vertices[0].GetType()).TextureCoordinates; for (var uv = 0; uv < numUvs; uv++) { var uvMap = new Dictionary <int, int>(); var deduplicatedUvs = new List <Vector2>(); UVDeduplicationMaps.Add(uvMap); DeduplicatedUVs.Add(deduplicatedUvs); for (var i = 0; i < vertices.Count; i++) { deduplicatedUvs.Add(vertices[i].GetUV(uv)); uvMap.Add(i, i); } } var numColors = Vertex.Description(vertices[0].GetType()).DiffuseColors; for (var color = 0; color < numColors; color++) { var colorMap = new Dictionary <int, int>(); var deduplicatedColors = new List <Vector4>(); ColorDeduplicationMaps.Add(colorMap); DeduplicatedColors.Add(deduplicatedColors); for (var i = 0; i < vertices.Count; i++) { deduplicatedColors.Add(vertices[i].GetColor(color)); colorMap.Add(i, i); } } }
private void ImportSkin(skin skin) { if (skin.source1[0] != '#') { throw new ParsingException("Only ID references are supported for skin geometries"); } Mesh mesh = null; if (!ColladaGeometries.TryGetValue(skin.source1.Substring(1), out mesh)) { throw new ParsingException("Skin references nonexistent mesh: " + skin.source1); } if (!Vertex.Description(mesh.VertexFormat).BoneWeights) { var msg = String.Format("Tried to apply skin to mesh ({0}) with non-skinned vertices ({1})", mesh.Name, mesh.VertexFormat.Name); throw new ParsingException(msg); } var sources = new Dictionary <String, Source>(); foreach (var source in skin.source) { var src = Source.FromCollada(source); sources.Add(src.id, src); } List <Bone> joints = null; List <Matrix4> invBindMatrices = null; foreach (var input in skin.joints.input) { if (input.source[0] != '#') { throw new ParsingException("Only ID references are supported for joint input sources"); } Source inputSource = null; if (!sources.TryGetValue(input.source.Substring(1), out inputSource)) { throw new ParsingException("Joint input source does not exist: " + input.source); } if (input.semantic == "JOINT") { List <string> jointNames = inputSource.NameParams.Values.SingleOrDefault(); if (jointNames == null) { throw new ParsingException("Joint input source 'JOINT' must contain array of names."); } var skeleton = Skeletons.Single(); joints = new List <Bone>(); foreach (var name in jointNames) { Bone bone = null; var lookupName = name.Replace("_x0020_", " "); if (!skeleton.BonesBySID.TryGetValue(lookupName, out bone)) { throw new ParsingException("Joint name list references nonexistent bone: " + lookupName); } joints.Add(bone); } } else if (input.semantic == "INV_BIND_MATRIX") { invBindMatrices = inputSource.MatrixParams.Values.SingleOrDefault(); if (invBindMatrices == null) { throw new ParsingException("Joint input source 'INV_BIND_MATRIX' must contain a single array of matrices."); } } else { throw new ParsingException("Unsupported joint semantic: " + input.semantic); } } if (joints == null) { throw new ParsingException("Required joint input semantic missing: JOINT"); } if (invBindMatrices == null) { throw new ParsingException("Required joint input semantic missing: INV_BIND_MATRIX"); } var influenceCounts = ColladaHelpers.StringsToIntegers(skin.vertex_weights.vcount); var influences = ColladaHelpers.StringsToIntegers(skin.vertex_weights.v); foreach (var count in influenceCounts) { if (count > 4) { throw new ParsingException("GR2 only supports at most 4 vertex influences"); } } // TODO if (influenceCounts.Count != mesh.OriginalToConsolidatedVertexIndexMap.Count) { Utils.Warn(String.Format("Vertex influence count ({0}) differs from vertex count ({1})", influenceCounts.Count, mesh.OriginalToConsolidatedVertexIndexMap.Count)); } List <Single> weights = null; int jointInputIndex = -1, weightInputIndex = -1; foreach (var input in skin.vertex_weights.input) { if (input.semantic == "JOINT") { jointInputIndex = (int)input.offset; } else if (input.semantic == "WEIGHT") { weightInputIndex = (int)input.offset; if (input.source[0] != '#') { throw new ParsingException("Only ID references are supported for weight input sources"); } Source inputSource = null; if (!sources.TryGetValue(input.source.Substring(1), out inputSource)) { throw new ParsingException("Weight input source does not exist: " + input.source); } if (!inputSource.FloatParams.TryGetValue("WEIGHT", out weights)) { weights = inputSource.FloatParams.Values.SingleOrDefault(); } if (weights == null) { throw new ParsingException("Weight input source " + input.source + " must have WEIGHT float attribute"); } } else { throw new ParsingException("Unsupported skin input semantic: " + input.semantic); } } if (jointInputIndex == -1) { throw new ParsingException("Required vertex weight input semantic missing: JOINT"); } if (weightInputIndex == -1) { throw new ParsingException("Required vertex weight input semantic missing: WEIGHT"); } // Remove bones that are not actually influenced from the binding list var boundBones = new HashSet <Bone>(); int offset = 0; int stride = skin.vertex_weights.input.Length; while (offset < influences.Count) { var jointIndex = influences[offset + jointInputIndex]; var weightIndex = influences[offset + weightInputIndex]; var joint = joints[jointIndex]; var weight = weights[weightIndex]; if (!boundBones.Contains(joint)) { boundBones.Add(joint); } offset += stride; } if (boundBones.Count > 255) { throw new ParsingException("GR2 supports at most 255 bound bones per mesh."); } mesh.BoneBindings = new List <BoneBinding>(); var boneToIndexMaps = new Dictionary <Bone, int>(); for (var i = 0; i < joints.Count; i++) { if (boundBones.Contains(joints[i])) { // Collada allows one inverse bind matrix for each skin, however Granny // only has one matrix for one bone, even if said bone is used from multiple meshes. // Hopefully the Collada ones are all equal ... var iwt = invBindMatrices[i]; // iwt.Transpose(); joints[i].InverseWorldTransform = new float[] { iwt[0, 0], iwt[1, 0], iwt[2, 0], iwt[3, 0], iwt[0, 1], iwt[1, 1], iwt[2, 1], iwt[3, 1], iwt[0, 2], iwt[1, 2], iwt[2, 2], iwt[3, 2], iwt[0, 3], iwt[1, 3], iwt[2, 3], iwt[3, 3] }; // Bind all bones that affect vertices to the mesh, so we can reference them // later from the vertexes BoneIndices. var binding = new BoneBinding(); binding.BoneName = joints[i].Name; // TODO binding.OBBMin = new float[] { -10, -10, -10 }; binding.OBBMax = new float[] { 10, 10, 10 }; mesh.BoneBindings.Add(binding); boneToIndexMaps.Add(joints[i], boneToIndexMaps.Count); } } offset = 0; for (var vertexIndex = 0; vertexIndex < influenceCounts.Count; vertexIndex++) { var influenceCount = influenceCounts[vertexIndex]; for (var i = 0; i < influenceCount; i++) { var jointIndex = influences[offset + jointInputIndex]; var weightIndex = influences[offset + weightInputIndex]; var joint = joints[jointIndex]; var weight = weights[weightIndex]; foreach (var consolidatedIndex in mesh.OriginalToConsolidatedVertexIndexMap[vertexIndex]) { var vertex = mesh.PrimaryVertexData.Vertices[consolidatedIndex]; vertex.AddInfluence((byte)boneToIndexMaps[joint], weight); } offset += stride; } } foreach (var vertex in mesh.PrimaryVertexData.Vertices) { vertex.FinalizeInfluences(); } // Warn if we have vertices that are not influenced by any bone int notInfluenced = 0; foreach (var vertex in mesh.PrimaryVertexData.Vertices) { if (vertex.BoneWeights[0] == 0) { notInfluenced++; } } if (notInfluenced > 0) { Utils.Warn(String.Format("{0} vertices are not influenced by any bone", notInfluenced)); } if (skin.bind_shape_matrix != null) { var bindShapeFloats = skin.bind_shape_matrix.Split(new char[] { ' ' }).Select(s => Single.Parse(s)).ToArray(); var mat = ColladaHelpers.FloatsToMatrix(bindShapeFloats); mat.Transpose(); BindShapeMatrix = mat; // Deform geometries that were affected by our bind shape matrix foreach (var vertex in mesh.PrimaryVertexData.Vertices) { vertex.Transform(BindShapeMatrix); } } else { BindShapeMatrix = Matrix4.Identity; } }
private Mesh ImportMesh(geometry geom, mesh mesh, string 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(); var components = new List <GrannyString>(); components.Add(new GrannyString("Position")); var vertexDesc = Vertex.Description(m.VertexFormat); if (vertexDesc.BoneWeights) { components.Add(new GrannyString("BoneWeights")); components.Add(new GrannyString("BoneIndices")); } if (vertexDesc.Normal) { components.Add(new GrannyString("Normal")); } if (vertexDesc.Tangent) { components.Add(new GrannyString("Tangent")); } if (vertexDesc.Binormal) { components.Add(new GrannyString("Binormal")); } for (int i = 0; i < vertexDesc.DiffuseColors; i++) { components.Add(new GrannyString("DiffuseColor" + i.ToString())); } for (int i = 0; i < vertexDesc.TextureCoordinates; i++) { components.Add(new GrannyString("TextureCoordinate" + i.ToString())); } m.PrimaryVertexData.VertexComponentNames = components; m.PrimaryVertexData.Vertices = collada.ConsolidatedVertices; 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; Utils.Info(String.Format("Imported {0} mesh ({1} tri groups, {2} tris)", (vertexDesc.BoneWeights ? "skinned" : "rigid"), m.PrimaryTopology.Groups.Count, collada.TriangleCount)); return(m); }
void computeTangents() { // Check if the vertex format has at least one UV set if (ConsolidatedVertices.Count() > 0) { var v = ConsolidatedVertices[0]; var descriptor = Vertex.Description(v.GetType()); if (descriptor.TextureCoordinates == 0) { throw new InvalidOperationException("At least one UV set is required to recompute tangents"); } } foreach (var v in ConsolidatedVertices) { v.Tangent = Vector3.Zero; v.Binormal = Vector3.Zero; } for (int i = 0; i < TriangleCount; i++) { var i1 = ConsolidatedIndices[i * 3 + 0]; var i2 = ConsolidatedIndices[i * 3 + 1]; var i3 = ConsolidatedIndices[i * 3 + 2]; var vert1 = ConsolidatedVertices[i1]; var vert2 = ConsolidatedVertices[i2]; var vert3 = ConsolidatedVertices[i3]; var v1 = vert1.Position; var v2 = vert2.Position; var v3 = vert3.Position; var w1 = vert1.TextureCoordinates0; var w2 = vert2.TextureCoordinates0; var w3 = vert3.TextureCoordinates0; float x1 = v2.X - v1.X; float x2 = v3.X - v1.X; float y1 = v2.Y - v1.Y; float y2 = v3.Y - v1.Y; float z1 = v2.Z - v1.Z; float z2 = v3.Z - v1.Z; float s1 = w2.X - w1.X; float s2 = w3.X - w1.X; float t1 = w2.Y - w1.Y; float t2 = w3.Y - w1.Y; float r = 1.0F / (s1 * t2 - s2 * t1); var sdir = new Vector3( (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r ); var tdir = new Vector3( (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r ); vert1.Tangent += sdir; vert2.Tangent += sdir; vert3.Tangent += sdir; vert1.Binormal += tdir; vert2.Binormal += tdir; vert3.Binormal += tdir; } foreach (var v in ConsolidatedVertices) { var n = v.Normal; var t = v.Tangent; var b = v.Binormal; // Gram-Schmidt orthogonalize var tangent = (t - n * Vector3.Dot(n, t)).Normalized(); // Calculate handedness var w = (Vector3.Dot(Vector3.Cross(n, t), b) < 0.0F) ? 1.0F : -1.0F; var binormal = (Vector3.Cross(n, t) * w).Normalized(); v.Tangent = tangent; v.Binormal = binormal; } }
public void ImportFromCollada(mesh mesh, string vertexFormat, bool isSkinned, ExporterOptions options) { Options = options; Mesh = mesh; ImportSources(); ImportFaces(); if (vertexFormat == null) { vertexFormat = FindVertexFormat(isSkinned); } VertexType = VertexFormatRegistry.Resolve(vertexFormat); 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.")); } computeNormals(); } ImportColors(); ImportUVs(); if (UVInputIndices.Count() > 0 || ColorInputIndices.Count() > 0) { 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(); 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 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 }); } } var description = Vertex.Description(VertexType); if ((description.Tangent && description.Binormal) && (!HasTangents || Options.RecalculateTangents)) { if (!HasTangents) { Utils.Info(String.Format("Channel 'TANGENT'/'BINROMAL' not found, will rebuild vertex tangents after import.")); } computeTangents(); } }