Exemplo n.º 1
0
 private void ImportSources()
 {
     Sources = new Dictionary <String, ColladaSource>();
     foreach (var source in Mesh.source)
     {
         var src = ColladaSource.FromCollada(source);
         Sources.Add(src.id, src);
     }
 }
Exemplo n.º 2
0
        private ColladaSource FindSource(string id)
        {
            if (id.Length == 0 || id[0] != '#')
            {
                throw new ParsingException("Only ID references are supported for input sources: " + id);
            }

            ColladaSource inputSource = null;

            if (!Sources.TryGetValue(id.Substring(1), out inputSource))
            {
                throw new ParsingException("Input source does not exist: " + id);
            }

            return(inputSource);
        }
Exemplo n.º 3
0
        private void ImportUVs()
        {
            bool flip = Options.FlipUVs;

            UVInputIndices.Clear();
            UVs = new List <List <Vector2> >();
            foreach (var input in Inputs)
            {
                if (input.semantic == "TEXCOORD")
                {
                    UVInputIndices.Add((int)input.offset);

                    if (input.source[0] != '#')
                    {
                        throw new ParsingException("Only ID references are supported for UV input sources");
                    }

                    ColladaSource inputSource = null;
                    if (!Sources.TryGetValue(input.source.Substring(1), out inputSource))
                    {
                        throw new ParsingException("UV input source does not exist: " + input.source);
                    }

                    List <Single> s = null, t = null;
                    if (!inputSource.FloatParams.TryGetValue("S", out s) ||
                        !inputSource.FloatParams.TryGetValue("T", out t))
                    {
                        throw new ParsingException("UV input source " + input.source + " must have S, T float attributes");
                    }

                    var uvs = new List <Vector2>();
                    UVs.Add(uvs);
                    for (var i = 0; i < s.Count; i++)
                    {
                        if (flip)
                        {
                            t[i] = 1.0f - t[i];
                        }
                        uvs.Add(new Vector2(s[i], t[i]));
                    }
                }
            }
        }
Exemplo n.º 4
0
        private void ImportColors()
        {
            ColorInputIndices.Clear();
            Colors = new List <List <Vector4> >();
            foreach (var input in Inputs)
            {
                if (input.semantic == "COLOR")
                {
                    ColorInputIndices.Add((int)input.offset);

                    if (input.source[0] != '#')
                    {
                        throw new ParsingException("Only ID references are supported for color input sources");
                    }

                    ColladaSource inputSource = null;
                    if (!Sources.TryGetValue(input.source.Substring(1), out inputSource))
                    {
                        throw new ParsingException("Color input source does not exist: " + input.source);
                    }

                    List <Single> r = null, g = null, b = null;
                    if (!inputSource.FloatParams.TryGetValue("R", out r) ||
                        !inputSource.FloatParams.TryGetValue("G", out g) ||
                        !inputSource.FloatParams.TryGetValue("B", out b))
                    {
                        if (!inputSource.FloatParams.TryGetValue("X", out r) ||
                            !inputSource.FloatParams.TryGetValue("Y", out g) ||
                            !inputSource.FloatParams.TryGetValue("Z", out b))
                        {
                            throw new ParsingException("Color input source " + input.source + " must have R, G, B float attributes");
                        }
                    }

                    var colors = new List <Vector4>();
                    Colors.Add(colors);
                    for (var i = 0; i < r.Count; i++)
                    {
                        colors.Add(new Vector4(r[i], g[i], b[i], 1.0f));
                    }
                }
            }
        }
Exemplo n.º 5
0
        public static List <Vector3> SourceToPositions(ColladaSource source)
        {
            List <Single> x = null, y = null, z = null;

            if (!source.FloatParams.TryGetValue("X", out x) ||
                !source.FloatParams.TryGetValue("Y", out y) ||
                !source.FloatParams.TryGetValue("Z", out z))
            {
                throw new ParsingException("Position source " + source.id + " must have X, Y, Z float attributes");
            }

            var positions = new List <Vector3>(x.Count);

            for (var i = 0; i < x.Count; i++)
            {
                positions.Add(new Vector3(x[i], y[i], z[i]));
            }

            return(positions);
        }
Exemplo n.º 6
0
        private void ImportSkin(Root root, 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 (!mesh.VertexFormat.HasBoneWeights)
            {
                var msg = String.Format("Tried to apply skin to mesh ({0}) with non-skinned vertices",
                                        mesh.Name);
                throw new ParsingException(msg);
            }

            var sources = new Dictionary <String, ColladaSource>();

            foreach (var source in skin.source)
            {
                var src = ColladaSource.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");
                }

                ColladaSource 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 = root.Skeletons[0];
                    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");
                    }

                    ColladaSource 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 > 127)
            {
                throw new ParsingException("D:OS supports at most 127 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
                    // Use small bounding box values, as it interferes with object placement
                    // in D:OS 2 (after the Gift Bag 2 update)
                    binding.OBBMin = new float[] { -0.1f, -0.1f, -0.1f };
                    binding.OBBMax = new float[] { 0.1f, 0.1f, 0.1f };
                    mesh.BoneBindings.Add(binding);
                    boneToIndexMaps.Add(joints[i], boneToIndexMaps.Count);
                }
            }

            offset = 0;
            for (var vertexIndex = 0; vertexIndex < influenceCounts.Count; vertexIndex++)
            {
                var   influenceCount = influenceCounts[vertexIndex];
                float influenceSum   = 0.0f;
                for (var i = 0; i < influenceCount; i++)
                {
                    var weightIndex = influences[offset + i * stride + weightInputIndex];
                    influenceSum += weights[weightIndex];
                }

                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] / influenceSum;
                    // Not all vertices are actually used in triangles, we may have unused verts in the
                    // source list (though this is rare) which won't show up in the consolidated vertex map.
                    if (mesh.OriginalToConsolidatedVertexIndexMap.TryGetValue(vertexIndex, out List <int> consolidatedIndices))
                    {
                        foreach (var consolidatedIndex in consolidatedIndices)
                        {
                            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.Trim().Split(new char[] { ' ' }).Select(s => Single.Parse(s)).ToArray();
                var bindShapeMat    = ColladaHelpers.FloatsToMatrix(bindShapeFloats);
                bindShapeMat.Transpose();

                // Deform geometries that were affected by our bind shape matrix
                mesh.PrimaryVertexData.Transform(bindShapeMat);
            }

            if (Options.RecalculateOBBs)
            {
                UpdateOBBs(root.Skeletons.Single(), mesh);
            }
        }
Exemplo n.º 7
0
        public static ColladaSource FromCollada(source src)
        {
            var source = new ColladaSource();

            source.id = src.id;

            var accessor = src.technique_common.accessor;
            // TODO: check src.#ID?

            float_array floats = null;
            Name_array  names  = null;

            if (src.Item is float_array)
            {
                floats = src.Item as float_array;
                // Workaround for empty arrays being null
                if (floats.Values == null)
                {
                    floats.Values = new double[] { }
                }
                ;

                if ((int)floats.count != floats.Values.Length || floats.count < accessor.stride * accessor.count + accessor.offset)
                {
                    throw new ParsingException("Float source data size mismatch. Check source and accessor item counts.");
                }
            }
            else if (src.Item is Name_array)
            {
                names = src.Item as Name_array;
                // Workaround for empty arrays being null
                if (names.Values == null)
                {
                    names.Values = new string[] { }
                }
                ;

                if ((int)names.count != names.Values.Length || names.count < accessor.stride * accessor.count + accessor.offset)
                {
                    throw new ParsingException("Name source data size mismatch. Check source and accessor item counts.");
                }
            }
            else
            {
                throw new ParsingException("Unsupported source data format.");
            }

            var paramOffset = 0;

            foreach (var param in accessor.param)
            {
                if (param.name == null)
                {
                    param.name = "default";
                }
                if (param.type == "float" || param.type == "double")
                {
                    var items  = new List <Single>((int)accessor.count);
                    var offset = (int)accessor.offset;
                    for (var i = 0; i < (int)accessor.count; i++)
                    {
                        items.Add((float)floats.Values[offset + paramOffset]);
                        offset += (int)accessor.stride;
                    }

                    source.FloatParams.Add(param.name, items);
                }
                else if (param.type == "float4x4")
                {
                    var items  = new List <Matrix4>((int)accessor.count);
                    var offset = (int)accessor.offset;
                    for (var i = 0; i < (int)accessor.count; i++)
                    {
                        var itemOff = offset + paramOffset;
                        var mat     = new Matrix4(
                            (float)floats.Values[itemOff + 0], (float)floats.Values[itemOff + 1], (float)floats.Values[itemOff + 2], (float)floats.Values[itemOff + 3],
                            (float)floats.Values[itemOff + 4], (float)floats.Values[itemOff + 5], (float)floats.Values[itemOff + 6], (float)floats.Values[itemOff + 7],
                            (float)floats.Values[itemOff + 8], (float)floats.Values[itemOff + 9], (float)floats.Values[itemOff + 10], (float)floats.Values[itemOff + 11],
                            (float)floats.Values[itemOff + 12], (float)floats.Values[itemOff + 13], (float)floats.Values[itemOff + 14], (float)floats.Values[itemOff + 15]
                            );
                        items.Add(mat);
                        offset += (int)accessor.stride;
                    }

                    source.MatrixParams.Add(param.name, items);
                }
                else if (param.type.ToLower() == "name")
                {
                    var items  = new List <String>((int)accessor.count);
                    var offset = (int)accessor.offset;
                    for (var i = 0; i < (int)accessor.count; i++)
                    {
                        items.Add(names.Values[offset + paramOffset]);
                        offset += (int)accessor.stride;
                    }

                    source.NameParams.Add(param.name, items);
                }
                else
                {
                    throw new ParsingException("Unsupported accessor param type: " + param.type);
                }

                paramOffset++;
            }

            return(source);
        }
    }
Exemplo n.º 8
0
        private void ImportVertices()
        {
            var vertexSemantics = new Dictionary <String, List <Vector3> >();

            foreach (var input in Mesh.vertices.input)
            {
                ColladaSource inputSource = FindSource(input.source);
                var           vertices    = ColladaHelpers.SourceToPositions(inputSource);
                vertexSemantics.Add(input.semantic, vertices);
            }

            List <Vector3> vertexPositions    = null;
            List <Vector3> perVertexNormals   = null;
            List <Vector3> perVertexTangents  = null;
            List <Vector3> perVertexBinormals = null;

            vertexSemantics.TryGetValue("POSITION", out vertexPositions);
            vertexSemantics.TryGetValue("NORMAL", out perVertexNormals);
            vertexSemantics.TryGetValue("TANGENT", out perVertexTangents);
            vertexSemantics.TryGetValue("BINORMAL", out perVertexBinormals);

            foreach (var input in Inputs)
            {
                if (input.semantic == "VERTEX")
                {
                    VertexInputIndex = (int)input.offset;
                }
                else if (input.semantic == "NORMAL")
                {
                    var normalsSource = FindSource(input.source);
                    Normals           = ColladaHelpers.SourceToPositions(normalsSource);
                    NormalsInputIndex = (int)input.offset;
                }
                else if (input.semantic == "TANGENT")
                {
                    var tangentsSource = FindSource(input.source);
                    Tangents           = ColladaHelpers.SourceToPositions(tangentsSource);
                    TangentsInputIndex = (int)input.offset;
                }
                else if (input.semantic == "BINORMAL")
                {
                    var binormalsSource = FindSource(input.source);
                    Binormals           = ColladaHelpers.SourceToPositions(binormalsSource);
                    BinormalsInputIndex = (int)input.offset;
                }
            }

            if (VertexInputIndex == -1)
            {
                throw new ParsingException("Required triangle input semantic missing: VERTEX");
            }

            Vertices = new List <Vertex>(vertexPositions.Count);
            for (var vert = 0; vert < vertexPositions.Count; vert++)
            {
                var vertex = OutputVertexType.CreateInstance();
                vertex.Position = vertexPositions[vert];

                if (perVertexNormals != null)
                {
                    vertex.Normal = perVertexNormals[vert];
                }

                if (perVertexTangents != null)
                {
                    vertex.Tangent = perVertexTangents[vert];
                }

                if (perVertexBinormals != null)
                {
                    vertex.Binormal = perVertexBinormals[vert];
                }

                Vertices.Add(vertex);
            }

            HasNormals  = perVertexNormals != null || NormalsInputIndex != -1;
            HasTangents = (perVertexTangents != null || TangentsInputIndex != -1) &&
                          (perVertexBinormals != null || BinormalsInputIndex != -1);
        }
Exemplo n.º 9
0
        private void ImportVertices()
        {
            var vertexSemantics = new Dictionary <String, List <Vector3> >();

            foreach (var input in Mesh.vertices.input)
            {
                if (input.source[0] != '#')
                {
                    throw new ParsingException("Only ID references are supported for vertex input sources");
                }

                ColladaSource inputSource = null;
                if (!Sources.TryGetValue(input.source.Substring(1), out inputSource))
                {
                    throw new ParsingException("Vertex input source does not exist: " + input.source);
                }

                List <Single> x = null, y = null, z = null;
                if (!inputSource.FloatParams.TryGetValue("X", out x) ||
                    !inputSource.FloatParams.TryGetValue("Y", out y) ||
                    !inputSource.FloatParams.TryGetValue("Z", out z))
                {
                    throw new ParsingException("Vertex input source " + input.source + " must have X, Y, Z float attributes");
                }

                var vertices = new List <Vector3>(x.Count);
                for (var i = 0; i < x.Count; i++)
                {
                    vertices.Add(new Vector3(x[i], y[i], z[i]));
                }

                vertexSemantics.Add(input.semantic, vertices);
            }

            List <Vector3> positions = null;
            List <Vector3> normals   = null;
            List <Vector3> tangents  = null;
            List <Vector3> binormals = null;

            vertexSemantics.TryGetValue("POSITION", out positions);
            vertexSemantics.TryGetValue("NORMAL", out normals);
            vertexSemantics.TryGetValue("TANGENT", out tangents);
            vertexSemantics.TryGetValue("BINORMAL", out binormals);

            int normalInputIndex = -1;

            foreach (var input in Inputs)
            {
                if (input.semantic == "VERTEX")
                {
                    VertexInputIndex = (int)input.offset;
                }
                else if (input.semantic == "NORMAL")
                {
                    normals          = new List <Vector3>();
                    normalInputIndex = (int)input.offset;

                    if (input.source[0] != '#')
                    {
                        throw new ParsingException("Only ID references are supported for Normal input sources");
                    }

                    ColladaSource inputSource = null;
                    if (!Sources.TryGetValue(input.source.Substring(1), out inputSource))
                    {
                        throw new ParsingException("Normal input source does not exist: " + input.source);
                    }

                    List <Single> x = null, y = null, z = null;
                    if (!inputSource.FloatParams.TryGetValue("X", out x) ||
                        !inputSource.FloatParams.TryGetValue("Y", out y) ||
                        !inputSource.FloatParams.TryGetValue("Z", out z))
                    {
                        throw new ParsingException("Normal input source " + input.source + " must have X, Y, Z float attributes");
                    }

                    for (var i = 0; i < x.Count; i++)
                    {
                        normals.Add(new Vector3(x[i], y[i], z[i]));
                    }
                }
            }

            if (VertexInputIndex == -1)
            {
                throw new ParsingException("Required triangle input semantic missing: VERTEX");
            }

            Vertices = new List <Vertex>(positions.Count);
            var vertexCtor = GR2.Helpers.GetConstructor(VertexType);

            for (var vert = 0; vert < positions.Count; vert++)
            {
                Vertex vertex = vertexCtor() as Vertex;
                vertex.Position = positions[vert];

                if (tangents != null)
                {
                    vertex.Tangent = tangents[vert];
                }

                if (binormals != null)
                {
                    vertex.Binormal = binormals[vert];
                }

                if (normals != null && normalInputIndex == -1)
                {
                    vertex.Normal = normals[vert];
                }

                Vertices.Add(vertex);
            }

            if (normalInputIndex != -1)
            {
                for (var vert = 0; vert < TriangleCount * 3; vert++)
                {
                    var vertexIndex = Indices[vert * InputOffsetCount + VertexInputIndex];
                    var normalIndex = Indices[vert * InputOffsetCount + normalInputIndex];

                    Vertex vertex = Vertices[vertexIndex];
                    vertex.Normal = normals[normalIndex];
                }
            }

            HasNormals  = normals != null;
            HasTangents = tangents != null && binormals != null;
        }