Exemplo n.º 1
0
        private int FindParent(List <Node> nodes)
        {
            BasePart part0 = StudioBone.Part0,
                     part1 = StudioBone.Part1;

            if (part0 != part1)
            {
                Node parent = null;

                foreach (Node n in nodes)
                {
                    StudioBone b = n.StudioBone;

                    if (b != StudioBone && b.Part1 == part0)
                    {
                        parent = n;
                        break;
                    }
                }

                return(nodes.IndexOf(parent));
            }

            return(-1);
        }
        private static void GenerateBones(BoneAssemblePrep prep, Attachment[] queue)
        {
            if (queue.Length == 0)
            {
                return;
            }

            Instance bin = queue[0].Parent.Parent;

            foreach (Attachment a0 in queue)
            {
                List <Attachment> a1s = FindOtherAttachments(a0, bin);

                foreach (Attachment a1 in a1s)
                {
                    if (a1 != null && !prep.Completed.Contains(a1))
                    {
                        BasePart part0 = (BasePart)a0.Parent;
                        BasePart part1 = (BasePart)a1.Parent;

                        bool isRigAttachment = a0.Name.EndsWith("RigAttachment", StringComparison.InvariantCulture);

                        if (isRigAttachment || prep.AllowNonRigs)
                        {
                            StudioBone bone = new StudioBone(part1.Name, part0, part1)
                            {
                                C0 = a0.CFrame,
                                C1 = a1.CFrame,
                            };

                            bone.IsAvatarBone = !prep.AllowNonRigs;
                            prep.Bones.Add(bone);

                            Node node = bone.Node;
                            node.NodeIndex = prep.Bones.IndexOf(bone);
                            prep.Nodes.Add(node);

                            if (!prep.Completed.Contains(a0))
                            {
                                prep.Completed.Add(a0);
                            }

                            prep.Completed.Add(a1);

                            if (!prep.AllowNonRigs)
                            {
                                GenerateBones(prep, part1.GetChildrenOfType <Attachment>());
                            }
                        }
                        else // We'll deal with Accessory attachments afterwards.
                        {
                            prep.NonRigs.Add(a0);
                        }
                    }
                }
            }
        }
        public static void BuildAvatarGeometry(StudioMdlWriter meshBuilder, StudioBone bone)
        {
            Contract.Requires(meshBuilder != null && bone != null);

            string task = "BuildGeometry_" + bone.Node.Name;

            Rbx2Source.ScheduleTasks(task);

            Node     node = bone.Node;
            BasePart part = bone.Part1;

            bool   isAvatarLimb = bone.IsAvatarBone;
            string matName      = part.Name;

            if (isAvatarLimb)
            {
                BodyPart?limb = GetLimb(part);

                if (!limb.HasValue)
                {
                    throw new ArgumentException("Provided StudioBone did not point to a limb correctly.");
                }

                matName = Rbx2Source.GetEnumName(limb.Value);
            }

            var material = new ValveMaterial()
            {
                UseAvatarMap = isAvatarLimb
            };

            Rbx2Source.Print("Building Geometry for {0}", part.Name);
            Rbx2Source.IncrementStack();

            Mesh geometry = Mesh.BakePart(part, material);

            meshBuilder.Materials[matName] = material;

            for (int i = 0; i < geometry.NumFaces; i++)
            {
                Triangle tri = new Triangle()
                {
                    Node      = node,
                    FaceIndex = i,
                    Mesh      = geometry,
                    Material  = matName
                };

                meshBuilder.Triangles.Add(tri);
            }

            Rbx2Source.DecrementStack();
            Rbx2Source.MarkTaskCompleted(task);
        }
Exemplo n.º 4
0
        public void WriteStudioMdl(StringWriter fileBuffer, List <BoneKeyframe> skeleton)
        {
            Contract.Requires(fileBuffer != null && skeleton != null);
            fileBuffer.WriteLine("time " + Time);

            foreach (StudioBone bone in Bones)
            {
                int boneIndex = Bones.IndexOf(bone);
                fileBuffer.Write(boneIndex + " ");

                int    parentIndex = bone.Node.ParentIndex;
                CFrame boneCFrame  = bone.C0;

                if (DeltaSequence)
                {
                    StudioBone refBone = BaseRig[boneIndex];
                    boneCFrame = refBone.C0 * boneCFrame;

                    Node refNode        = refBone.Node;
                    int  refParentIndex = refNode.ParentIndex;

                    if (refParentIndex >= 0)
                    {
                        StudioBone refParent = BaseRig[refParentIndex];
                        boneCFrame = refParent.C1.Inverse() * boneCFrame;
                    }
                }
                else if (parentIndex >= 0)
                {
                    StudioBone parentBone = Bones[parentIndex];
                    boneCFrame *= parentBone.C1.Inverse();
                }

                Vector3 pos = boneCFrame.Position * Rbx2Source.MODEL_SCALE;
                Vector3 rot = new Vector3(boneCFrame.ToEulerAnglesXYZ());

                fileBuffer.Write(Format.FormatFloats
                                 (
                                     pos.X, pos.Y, pos.Z,
                                     rot.X, rot.Y, rot.Z
                                 ));

                fileBuffer.WriteLine();
            }
        }
        public static BoneKeyframe AssembleBones(StudioMdlWriter meshBuilder, BasePart rootPart)
        {
            Contract.Requires(meshBuilder != null);
            Contract.Requires(rootPart != null);

            Rbx2Source.Print("Building Skeleton...");
            BoneKeyframe kf = new BoneKeyframe();

            List <StudioBone> bones = kf.Bones;
            List <Node>       nodes = meshBuilder.Nodes;

            StudioBone rootBone = new StudioBone(rootPart.Name, rootPart)
            {
                C0           = new CFrame(),
                IsAvatarBone = true
            };

            Node rootNode = rootBone.Node;

            rootNode.NodeIndex = 0;

            bones.Add(rootBone);
            nodes.Add(rootNode);

            // Assemble the base rig.
            BoneAssemblePrep prep = new BoneAssemblePrep(ref bones, ref nodes);

            GenerateBones(prep, rootPart.GetChildrenOfType <Attachment>());

            // Assemble the accessories.
            prep.AllowNonRigs = true;
            GenerateBones(prep, prep.NonRigs.ToArray());

            // Apply the rig cframe data.
            ApplyBoneCFrames(rootPart);
            meshBuilder.Skeleton.Add(kf);

            return(kf);
        }
Exemplo n.º 6
0
        public static string Assemble(KeyframeSequence sequence, List <StudioBone> rig)
        {
            Contract.Requires(sequence != null && rig != null);

            StudioMdlWriter animWriter = new StudioMdlWriter();
            List <Keyframe> keyframes  = new List <Keyframe>();

            var boneLookup = new Dictionary <string, StudioBone>();
            var nodes      = animWriter.Nodes;

            foreach (StudioBone bone in rig)
            {
                Node node = bone.Node;

                if (node != null)
                {
                    string boneName = node.Name;

                    if (!boneLookup.ContainsKey(boneName))
                    {
                        boneLookup.Add(boneName, bone);
                    }

                    nodes.Add(node);
                }
            }

            foreach (Keyframe kf in sequence.GetChildrenOfType <Keyframe>())
            {
                Pose rootPart = kf.FindFirstChild <Pose>("HumanoidRootPart");

                if (rootPart != null)
                {
                    // We don't need the rootpart for this.
                    foreach (Pose subPose in rootPart.GetChildrenOfType <Pose>())
                    {
                        subPose.Parent = kf;
                    }

                    rootPart.Destroy();
                }

                keyframes.Add(kf);
            }

            keyframes.Sort(0, keyframes.Count, sorter);

            Keyframe lastKeyframe = keyframes[keyframes.Count - 1];

            float fLength    = lastKeyframe.Time;
            int   frameCount = ToFrameRate(fLength);

            // As far as I can tell, models in Source require you to store poses for every
            // single frame, so I need to fill in the gaps with interpolated pose CFrames.

            var keyframeMap = new Dictionary <int, Dictionary <string, Pose> >();

            foreach (Keyframe kf in keyframes)
            {
                int frame = ToFrameRate(kf.Time);
                var poses = GatherPoses(kf);

                var poseMap = poses.ToDictionary(pose => pose.Name);
                keyframeMap[frame] = poseMap;
            }

            // Make sure there are no holes in the data.
            for (int i = 0; i < frameCount; i++)
            {
                if (!keyframeMap.ContainsKey(i))
                {
                    var emptyState = new Dictionary <string, Pose>();
                    keyframeMap.Add(i, emptyState);
                }
            }

            List <BoneKeyframe> boneKeyframes = animWriter.Skeleton;

            for (int i = 0; i < frameCount; i++)
            {
                var frame = new BoneKeyframe(i);
                List <StudioBone> bones = frame.Bones;
                var avatarTypeId        = sequence.FindFirstChild <StringValue>("AvatarType");

                if (avatarTypeId.Value == "R15")
                {
                    frame.BaseRig       = rig;
                    frame.DeltaSequence = true;
                }

                foreach (Node node in nodes)
                {
                    PosePair closestPoses = GetClosestPoses(keyframeMap, i, node.Name);

                    float min = closestPoses.Min.Frame;
                    float max = closestPoses.Max.Frame;

                    float alpha = (min == max ? 0 : (i - min) / (max - min));

                    Pose pose0 = closestPoses.Min.Pose;
                    Pose pose1 = closestPoses.Max.Pose;

                    CFrame lastCFrame = pose0.CFrame;
                    CFrame nextCFrame = pose1.CFrame;

                    StudioBone baseBone = boneLookup[node.Name];
                    CFrame     interp   = lastCFrame.Lerp(nextCFrame, alpha);

                    // Make some patches to the interpolation offsets. Unfortunately I can't
                    // identify any single fix that I can apply to each joint, so I have to get crafty.
                    // At some point in the future, I want to find a more practical solution for this problem,
                    // but it is extremely difficult to isolate if any single solution exists.

                    var invariant = StringComparison.InvariantCulture;

                    if (avatarTypeId.Value == "R6")
                    {
                        Vector3 pos = interp.Position;
                        CFrame  rot = interp - pos;

                        if (node.Name == "Torso")
                        {
                            // Flip the YZ axis of the Torso.
                            float[] ang = interp.ToEulerAnglesXYZ();
                            rot = CFrame.Angles(ang[0], ang[2], ang[1]);
                            pos = new Vector3(pos.X, pos.Z, pos.Y);
                        }
                        else if (node.Name.StartsWith("Right", invariant))
                        {
                            // X-axis is inverted for the right arm/leg.
                            pos *= new Vector3(-1, 1, 1);
                        }

                        if (node.Name.EndsWith("Arm", invariant) || node.Name.EndsWith("Leg", invariant))
                        {
                            // Rotate position offset of the arms & legs 90* counter-clockwise.
                            pos = new Vector3(-pos.Z, pos.Y, pos.X);
                        }

                        if (node.Name != "Head")
                        {
                            rot = rot.Inverse();
                        }

                        interp = new CFrame(pos) * rot;
                    }
                    else if (avatarTypeId.Value == "R15")
                    {
                        float[] ang = interp.ToEulerAnglesXYZ();

                        // Cancel out the rotations
                        interp *= CFrame.Angles(-ang[0], -ang[1], -ang[2]);

                        // Patch the Y-axis
                        PatchAngles(ref interp, 1, ang);

                        // Patch the Z-axis
                        PatchAngles(ref interp, 2, ang);

                        // Patch the X-axis
                        PatchAngles(ref interp, 0, ang);
                    }

                    StudioBone bone = new StudioBone(node, interp);
                    bones.Add(bone);
                }

                boneKeyframes.Add(frame);
            }

            string result = animWriter.BuildFile();

            animWriter.Dispose();

            return(result);
        }
Exemplo n.º 7
0
        public static StudioMdlWriter AssembleModel(Asset asset)
        {
            Contract.Requires(asset != null);

            var content = asset.OpenAsModel();

            Rbx2Source.ScheduleTasks("GatherParts", "BuildMesh");

            List <BasePart> parts = new List <BasePart>();

            AddParts(parts, content);

            if (parts.Count == 0)
            {
                throw new Exception("No parts were found inside of this asset!");
            }

            BasePart primaryPart = null;

            foreach (BasePart part in parts)
            {
                if (part is MeshPart || part.Name == "Handle")
                {
                    primaryPart = part;
                    break;
                }
            }

            if (primaryPart == null) // k lol
            {
                primaryPart = parts[0];
            }

            primaryPart.Name = asset.ProductInfo.WindowsSafeName.Trim();

            // Mark the primaryPart's location as the center.
            CFrame rootCoord = primaryPart.CFrame;

            foreach (BasePart part in parts)
            {
                part.CFrame = rootCoord.ToObjectSpace(part.CFrame);
            }

            Rbx2Source.MarkTaskCompleted("GatherParts");
            Rbx2Source.PrintHeader("BUILDING MESH");

            StudioMdlWriter writer = new StudioMdlWriter();

            BoneKeyframe skeleton = new BoneKeyframe();

            writer.Skeleton.Add(skeleton);

            List <StudioBone> bones = skeleton.Bones;
            List <Node>       nodes = writer.Nodes;

            List <Triangle> triangles         = writer.Triangles;
            int             numAssembledParts = 0;

            var materials  = writer.Materials;
            var nameCounts = new Dictionary <string, int>();

            foreach (BasePart part in parts)
            {
                // Make sure this part has a unique name.
                string name = part.Name;

                if (nameCounts.ContainsKey(name))
                {
                    int count = ++nameCounts[name];
                    name     += count.ToInvariantString();
                    part.Name = name;
                }
                else
                {
                    nameCounts[name] = 0;
                }

                // Assemble the part.
                var  material = new ValveMaterial();
                Mesh geometry = Mesh.BakePart(part, material);

                if (geometry != null && geometry.NumFaces > 0)
                {
                    string task = "BuildGeometry_" + name;
                    Rbx2Source.ScheduleTasks(task);
                    Rbx2Source.Print("Building Geometry for {0}", name);

                    var bone = new StudioBone(name, primaryPart, part)
                    {
                        C0 = part.CFrame
                    };
                    bones.Add(bone);

                    Node node = bone.Node;
                    nodes.Add(node);

                    int faceStride;
                    materials.Add(name, material);

                    if (geometry.HasLODs)
                    {
                        faceStride = geometry.LODs[1];
                    }
                    else
                    {
                        faceStride = geometry.NumFaces;
                    }

                    for (int i = 0; i < faceStride; i++)
                    {
                        Triangle tri = new Triangle()
                        {
                            Node      = node,
                            Mesh      = geometry,
                            FaceIndex = i,
                            Material  = name,
                        };

                        triangles.Add(tri);
                    }

                    Rbx2Source.MarkTaskCompleted(task);
                    numAssembledParts++;
                }
            }


            Rbx2Source.MarkTaskCompleted("BuildMesh");
            return(writer);
        }