Пример #1
0
        /// <summary>
        /// reads a bvh node from a given bvh reader
        /// </summary>
        /// <param name="reader">stream reader standing on the opening parantheses of a node definition</param>
        /// <param name="idLine">line containing the name of the node</param>
        /// <param name="depth">recursion depth of the current node</param>
        private static BVHNode ReadNode(StreamReader reader, string idLine, int depth)
        {
            BVHNode node = new BVHNode();

            // read node type and name
            var line = idLine.ToLower().Trim();

            string[] tokens = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

            string nodeType = tokens[0];
            string nodeName = tokens[1];

            BVHNodeTypes type;

            if (nodeType == "end" && nodeName == "site")
            {
                type = BVHNodeTypes.EndSite;
            }
            else
            {
                if (!Enum.TryParse <BVHNodeTypes>(nodeType, true, out type))
                {
                    throw new FileFormatException($"Invalid Bvh Node Type: {nodeType}");
                }
            }

            node.Type = type;
            node.Name = nodeName;

            // read starting curly brace {
            reader.ReadLine();

            node.Offset = ReadOffset(reader);

            if (node.Type != BVHNodeTypes.EndSite)
            {
                node.Channels = ReadChannels(reader);
            }


            while (true)
            {
                line = reader.ReadLine().ToLower().Trim();

                if (line == "}")
                {
                    return(node);
                }
                else
                {
                    node.Children.Add(ReadNode(reader, line, depth + 1));
                }
            }
        }
Пример #2
0
        /// <summary>
        /// recursively write a BVH node an all its children to a BVH motion data file
        /// </summary>
        private static void WriteBvhNode(BVHNode node, StreamWriter writer, int level)
        {
            // name and type
            for (int i = 0; i < level - 1; ++i)
            {
                writer.Write("\t");
            }
            writer.WriteLine($"{GetTypeString(node.Type)} {node.Name}");

            // open curly bracket
            for (int i = 0; i < level - 1; ++i)
            {
                writer.Write("\t");
            }
            writer.WriteLine("{");

            // node offset
            for (int i = 0; i < level; ++i)
            {
                writer.Write("\t");
            }
            writer.WriteLine($"OFFSET {node.Offset.X} {node.Offset.Y} {node.Offset.Z}");

            if (node.Type != BVHNodeTypes.EndSite)
            {
                // defined channels
                for (int i = 0; i < level; ++i)
                {
                    writer.Write("\t");
                }
                writer.Write($"CHANNELS {node.Channels.Length} ");

                foreach (var chan in node.Channels)
                {
                    writer.Write(chan.ToString() + " ");
                }
                writer.Write(Environment.NewLine);

                // child nodes
                foreach (var child in node.Children)
                {
                    WriteBvhNode(child, writer, level + 1);
                }
            }

            // closing curly bracket
            for (int i = 0; i < level - 1; ++i)
            {
                writer.Write("\t");
            }
            writer.WriteLine("}");
        }
Пример #3
0
        /// <summary>
        /// read motion data from a bvh file, starting with the MOTION keyword
        /// </summary>
        public static BVHMotionData ReadMotionData(StreamReader reader, BVHNode root)
        {
            var line = reader.ReadLine().ToLower().Trim();

            if (line != "motion")
            {
                throw new FileFormatException("Expected MOTION keyword");
            }

            // read number of frames
            line = reader.ReadLine().ToLower().Trim();
            var tokens = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

            int numFrames;

            if (!int.TryParse(tokens[1], out numFrames))
            {
                throw new FileFormatException("Could not read number of frames");
            }

            //read frame time
            line   = reader.ReadLine().ToLower().Trim();
            tokens = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

            double frameTime;

            if (!double.TryParse(tokens[2], out frameTime))
            {
                throw new FileFormatException("Could not read frame time");
            }

            // read all frame data
            Dictionary <BVHNode, List <Quaternion> > motionData = new Dictionary <BVHNode, List <Quaternion> >();

            while (!reader.EndOfStream)
            {
                line = reader.ReadLine().ToLower().Trim();
                if (String.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                double[] frameData = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries).Select(t => double.Parse(t)).ToArray();

                // interpret frame-by-frame
                int offset = 0;
                ReadFrameData(root, motionData, frameData, ref offset);
            }

            return(new BVHMotionData(frameTime, motionData));
        }
Пример #4
0
        /// <summary>
        /// converts BVH hierarchical structure to the applications own kinematic model definition
        /// </summary>
        public static Bone ToBones(BVHNode bvhNode, Bone parent, BVHMotionData bvhMotionData,
                                   MotionData resultMotionData)
        {
            Bone result = new Bone(parent, name: bvhNode.Name, offset: bvhNode.Offset);

            if (bvhNode.Type != BVHNodeTypes.EndSite)
            {
                resultMotionData.Data.Add(result, bvhMotionData.Data[bvhNode].ToList());
            }

            foreach (BVHNode item in bvhNode.Children)
            {
                result.Children.Add(ToBones(item, result, bvhMotionData, resultMotionData));
            }

            return(result);
        }
Пример #5
0
        /// <summary>
        /// interprets motion data for a single frame
        /// </summary>
        private static void ReadFrameData(BVHNode node, Dictionary <BVHNode, List <Quaternion> > motionData, double[] values, ref int offset)
        {
            if (node.Type == BVHNodeTypes.EndSite)
            {
                return;
            }

            double[] nodevalues = new double[node.Channels.Length];
            Array.Copy(values, offset, nodevalues, 0, node.Channels.Length);
            offset += node.Channels.Length;

            if (!motionData.ContainsKey(node))
            {
                motionData.Add(node, new List <Quaternion>());
            }

            // TODO: add support for position in Bones/check how many channels really have to be skipped
            int ignoredOffset = 0;

            if (node.Channels[0] == BVHChannels.Xposition)
            {
                ignoredOffset += 3;
            }

            // convert rotation to quaternion
            var q1 = new Quaternion(GetAxisFromChannelType(node.Channels[ignoredOffset]), nodevalues[ignoredOffset]);
            var q2 = new Quaternion(GetAxisFromChannelType(node.Channels[ignoredOffset + 1]), nodevalues[ignoredOffset + 1]);
            var q3 = new Quaternion(GetAxisFromChannelType(node.Channels[ignoredOffset + 2]), nodevalues[ignoredOffset + 2]);

            Quaternion quat = q1 * q2 * q3;

            motionData[node].Add(quat);

            foreach (var item in node.Children)
            {
                ReadFrameData(item, motionData, values, ref offset);
            }
        }
Пример #6
0
        /// <summary>
        /// converts a kinematic model to BVH structure for export.
        /// </summary>
        private static BVHNode ToBVHNode(Bone bone, Dictionary <Bone, List <Quaternion> > sourceMotionData, BVHNode parent, Dictionary <BVHNode, List <Quaternion> > motionData)
        {
            var result = new BVHNode();

            result.Name   = bone.Name;
            result.Offset = bone.Offset;

            // determine type
            if (parent == null)
            {
                result.Type     = BVHNodeTypes.Root;
                result.Channels = new[] { BVHChannels.Zrotation, BVHChannels.Yrotation, BVHChannels.Xrotation };
            }
            else if (bone.Children.Count == 0)
            {
                result.Type = BVHNodeTypes.EndSite;
            }
            else
            {
                result.Type     = BVHNodeTypes.Joint;
                result.Channels = new[] { BVHChannels.Zrotation, BVHChannels.Yrotation, BVHChannels.Xrotation };
            }

            // populate motion data
            if (result.Type != BVHNodeTypes.EndSite)
            {
                motionData.Add(result, sourceMotionData[bone]);
            }

            // add child nodes
            foreach (var child in bone.Children)
            {
                result.Children.Add(ToBVHNode(child, sourceMotionData, result, motionData));
            }

            return(result);
        }
Пример #7
0
        /// <summary>
        /// Writes a BVH motion data file
        /// </summary>
        public static void WriteBvh(string file, BVHNode root, BVHMotionData motionData)
        {
            using (var writer = new StreamWriter(file))
            {
                writer.WriteLine("HIERARCHY");
                WriteBvhNode(root, writer, 0);
                writer.WriteLine("MOTION");

                int numFrames = motionData.Data.First().Value.Count;
                writer.WriteLine($"Frames: {numFrames}");
                writer.WriteLine($"Frame Time: {motionData.FrameTime}");
                for (int i = 0; i < numFrames; i++)
                {
                    foreach (var node in motionData.Data.Keys)
                    {
                        double yaw, pitch, roll;
                        motionData.Data[node][i].ToYawPitchRoll(out yaw, out pitch, out roll);

                        writer.Write($"{yaw * 180 / Math.PI} {pitch * 180 / Math.PI} {roll * 180 / Math.PI} ");
                    }
                    writer.WriteLine();
                }
            }
        }