Exemple #1
0
        // Set to binding pose ("T" pose)
        public static void SetToBindingPose([NotNull] this PmxBone bone)
        {
            if (bone.IsTransformCalculated)
            {
                return;
            }

            var parent = bone.Parent;

            Vector3 localPosition;

            if (parent == null)
            {
                localPosition = bone.InitialPosition;
            }
            else
            {
                parent.SetToBindingPose();
                localPosition = bone.InitialPosition - parent.InitialPosition;
            }

            bone.LocalMatrix = CalculateTransform(localPosition, Quaternion.Identity);
            bone.WorldMatrix = bone.CalculateWorldMatrix();

            bone.IsTransformCalculated = true;
        }
Exemple #2
0
        // https://github.com/sn0w75/MMP/blob/master/libmmp/motioncontroller.cpp
        internal static void SetToVmdPose([NotNull] this PmxBone bone)
        {
            if (bone.IsTransformCalculated)
            {
                return;
            }

            bone.CurrentRotation = bone.AnimatedRotation;

            var parent = bone.ParentBone;

            Vector3 localPosition;

            if (parent == null)
            {
                localPosition = bone.AnimatedTranslation + bone.InitialPosition;
            }
            else
            {
                parent.SetToVmdPose();
                localPosition = bone.AnimatedTranslation + bone.InitialPosition - parent.InitialPosition;
            }

            bone.LocalMatrix = CalculateTransform(localPosition, bone.CurrentRotation);
            bone.WorldMatrix = bone.CalculateWorldMatrix();

            bone.IsTransformCalculated = true;
        }
Exemple #3
0
        public void UpdateMatrix(int frame)
        {
            var pos = DxMath.Vector3.Zero;
            var rot = DxMath.Quaternion.Identity;

            foreach (var layer in MMMBone.Layers)
            {
                var data = layer.Frames.GetFrame(frame);
                pos += data.Position;
                rot *= data.Quaternion;
            }

            PmxBone.Pos = Pos = pos.Convert();
            PmxBone.Rot = Rot = rot.Convert();

            foreach (var bone in ParentBones)
            {
                bone.UpdateMatrix(frame);
            }

            PmxBone.UpdateLocalMatrix();
            PmxBone.UpdateWorldMatrix();

            LocalMat        = PmxBone.LocalMat;
            CurrentWorldMat = new Matrix4(LocalCoordinate * PmxBone.WorldMat.Rotation, PmxBone.WorldMat.Translation);
        }
Exemple #4
0
        internal static void SetToVmdPose([NotNull] this PmxBone bone, bool forced = false)
        {
            if (!forced && bone.IsTransformCalculated)
            {
                return;
            }

            // Ignore append parent.

            bone.CurrentRotation = bone.AnimatedRotation;

            var parent = bone.Parent;

            Vector3 localPosition;

            if (parent == null)
            {
                localPosition = bone.AnimatedTranslation + bone.InitialPosition;
            }
            else
            {
                parent.SetToVmdPose();
                localPosition = bone.AnimatedTranslation + bone.InitialPosition - parent.InitialPosition;
            }

            bone.LocalMatrix = CalculateTransform(localPosition, bone.CurrentRotation);
            bone.WorldMatrix = bone.CalculateWorldMatrix();

            bone.SkinMatrix = bone.BindingPoseMatrixInverse * bone.WorldMatrix;

            bone.CurrentPosition = Vector3.TransformPosition(bone.InitialPosition, bone.SkinMatrix);

            bone.IsTransformCalculated = true;
        }
Exemple #5
0
        internal static void SetInitialRotationFromRotationAxes([NotNull] this PmxBone bone, Vector3 localX, Vector3 localY, Vector3 localZ)
        {
            var rotationMatrix = new Matrix3(
                localX.X, localX.Y, localX.Z,
                localY.X, localY.Y, localY.Z,
                localZ.X, localZ.Y, localZ.Z);

            bone.InitialRotation = Quaternion.FromMatrix(rotationMatrix);
            bone.CurrentRotation = bone.InitialRotation;
        }
Exemple #6
0
        private void WritePmxBone([NotNull] PmxBone bone)
        {
            WriteString(bone.Name);
            WriteString(bone.NameEnglish);

            _writer.Write(bone.InitialPosition);
            _writer.WriteInt32AsVarLenInt(bone.ParentIndex, BoneElementSize);
            _writer.Write(bone.Level);
            _writer.Write((ushort)bone.Flags);

            if (bone.HasFlag(BoneFlags.ToBone))
            {
                _writer.WriteInt32AsVarLenInt(bone.To_Bone, BoneElementSize);
            }
            else
            {
                _writer.Write(bone.To_Offset);
            }

            if (bone.HasFlag(BoneFlags.AppendRotation) || bone.HasFlag(BoneFlags.AppendTranslation))
            {
                _writer.WriteInt32AsVarLenInt(bone.AppendParentIndex, BoneElementSize);
                _writer.Write(bone.AppendRatio);
            }

            if (bone.HasFlag(BoneFlags.FixedAxis))
            {
                _writer.Write(bone.Axis);
            }

            if (bone.HasFlag(BoneFlags.LocalFrame))
            {
                var rotation = bone.InitialRotation;
                var mat      = Matrix4.CreateFromQuaternion(rotation);

                var localX = mat.Row0.Xyz;
                var localZ = mat.Row2.Xyz;

                localX.Normalize();
                localZ.Normalize();

                _writer.Write(localX);
                _writer.Write(localZ);
            }

            if (bone.HasFlag(BoneFlags.ExternalParent))
            {
                _writer.Write(bone.ExternalParentIndex);
            }

            if (bone.HasFlag(BoneFlags.IK) && bone.IK != null)
            {
                WritePmxIK(bone.IK);
            }
        }
Exemple #7
0
 public static void SetFlag([NotNull] this PmxBone bone, BoneFlags flags, bool set)
 {
     if (set)
     {
         SetFlag(bone, flags);
     }
     else
     {
         ClearFlag(bone, flags);
     }
 }
Exemple #8
0
 private static Matrix CalculateWorldMatrix([NotNull] this PmxBone bone)
 {
     if (bone.ParentBone != null)
     {
         return(bone.LocalMatrix * bone.ParentBone.WorldMatrix);
     }
     else
     {
         return(bone.LocalMatrix);
     }
 }
Exemple #9
0
 public static Matrix4 CalculateWorldMatrix([NotNull] this PmxBone bone)
 {
     if (bone.Parent == null)
     {
         return(bone.LocalMatrix);
     }
     else
     {
         return(bone.LocalMatrix * bone.Parent.WorldMatrix);
     }
 }
 private void CreateBoneList()
 {
     for (int i = 0; i < this.boneList.Count; i++)
     {
         Transform bone    = this.boneList[i];
         PmxBone   pmxBone = new PmxBone();
         pmxBone.Name  = bone.name;
         pmxBone.NameE = bone.name;
         if (this.boneParent[i] >= 0)
         {
             pmxBone.Parent = this.boneParent[i];
         }
         UnityEngine.Vector3 vector = bone.position * scaleFactor;
         pmxBone.Position = ToPmxVec3(vector);
         this.pmxFile.BoneList.Add(pmxBone);
     }
 }
        private void CreateBoneList()
        {
            List <PmxBone> pmxBoneList = pmxFile.BoneList;

            for (int i = 0; i < boneList.Count; i++)
            {
                Transform bone    = boneList[i];
                PmxBone   pmxBone = new PmxBone();
                pmxBone.Name  = bone.name;
                pmxBone.NameE = bone.name;
                if (boneParent[i] >= 0)
                {
                    pmxBone.Parent = boneParent[i];
                }
                UnityEngine.Vector3 vector = bone.position * scaleFactor;
                pmxBone.Position  = ToPmxVec3(vector);
                pmxBone.To_Offset = ToPmxVec3(bone.rotation * UnityEngine.Vector3.left * scaleFactor / 16f);
                if (bone.name.EndsWith("_SCL_") || bone.name.Contains("twist"))
                {
                    pmxBone.SetFlag(PmxBone.BoneFlags.Visible, false);
                }
                pmxBoneList.Add(pmxBone);
            }

            for (int i = 0; i < pmxBoneList.Count; i++)
            {
                PmxBone pmxBone        = pmxBoneList[i];
                int     children       = 0;
                int     lastChildIndex = -1;
                for (int j = 0; j < pmxBoneList.Count; j++)
                {
                    PmxBone pmxOtherBone = pmxBoneList[j];
                    if (pmxOtherBone.Parent == i && pmxOtherBone.GetFlag(PmxBone.BoneFlags.Visible))
                    {
                        children++;
                        lastChildIndex = j;
                    }
                }
                if (children == 1)
                {
                    Debug.Log($"Pointing Bone {pmxBone.NameE} to {pmxBoneList[lastChildIndex].NameE}");
                    pmxBone.SetFlag(PmxBone.BoneFlags.ToBone, true);
                    pmxBone.To_Bone = lastChildIndex;
                }
            }
        }
Exemple #12
0
        private PmxBone ReadPmxBone()
        {
            var bone = new PmxBone();

            bone.Name            = ReadString() ?? string.Empty;
            bone.NameEnglish     = ReadString() ?? string.Empty;
            bone.InitialPosition = _reader.ReadVector3();
            bone.CurrentPosition = bone.InitialPosition;
            bone.ParentIndex     = _reader.ReadVarLenIntAsInt32(BoneElementSize);
            bone.Level           = _reader.ReadInt32();
            bone.Flags           = (BoneFlags)_reader.ReadUInt16();

            if (bone.HasFlag(BoneFlags.ToBone))
            {
                bone.To_Bone = _reader.ReadVarLenIntAsInt32(BoneElementSize);
            }
            else
            {
                bone.To_Offset = _reader.ReadVector3();
            }

            if (bone.HasFlag(BoneFlags.AppendRotation) || bone.HasFlag(BoneFlags.AppendTranslation))
            {
                bone.AppendParentIndex = _reader.ReadVarLenIntAsInt32(BoneElementSize);
                bone.AppendRatio       = _reader.ReadSingle();
            }

            if (bone.HasFlag(BoneFlags.FixedAxis))
            {
                bone.Axis = _reader.ReadVector3();
            }

            if (bone.HasFlag(BoneFlags.LocalFrame))
            {
                var localX = _reader.ReadVector3();
                var localZ = _reader.ReadVector3();

                localX.Normalize();
                localZ.Normalize();

                var localY = Vector3.Cross(localZ, localX);

                localZ = Vector3.Cross(localX, localY);
                localY.Normalize();
                localZ.Normalize();

                bone.SetInitialRotationFromRotationAxes(localX, localY, localZ);
            }
            else
            {
                bone.InitialRotation = Quaternion.Identity;
                bone.CurrentRotation = Quaternion.Identity;
            }

            if (bone.HasFlag(BoneFlags.ExternalParent))
            {
                bone.ExternalParentIndex = _reader.ReadInt32();
            }

            if (bone.HasFlag(BoneFlags.IK))
            {
                bone.IK = ReadPmxIK();
            }

            return(bone);
        }
Exemple #13
0
 public static void SetVmdAnimation([NotNull] this PmxBone bone, Vector3 vmdTranslation, Quaternion vmdRotation)
 {
     bone.AnimatedTranslation = vmdTranslation;
     bone.AnimatedRotation    = vmdRotation;
 }
Exemple #14
0
 public static bool HasFlag([NotNull] this PmxBone bone, BoneFlags flags)
 {
     return((bone.Flags & flags) != 0);
 }
Exemple #15
0
 internal static void UpdateSkinMatrix([NotNull] this PmxBone bone)
 {
     bone.SkinMatrix      = bone.BindPoseMatrixInverse * bone.WorldMatrix;
     bone.CurrentPosition = Vector3.Transform(bone.InitialPosition, bone.SkinMatrix);
 }
Exemple #16
0
 public static void ClearFlag([NotNull] this PmxBone bone, BoneFlags flags)
 {
     bone.Flags &= ~flags;
 }
Exemple #17
0
 public static void SetFlag([NotNull] this PmxBone bone, BoneFlags flags)
 {
     bone.Flags |= flags;
 }
Exemple #18
0
        private static IReadOnlyList <PmxBone> AddBones([NotNull] Avatar combinedAvatar, [NotNull] Mesh combinedMesh, [NotNull, ItemNotNull] IReadOnlyList <PmxVertex> vertices)
        {
            var boneCount = combinedAvatar.AvatarSkeleton.NodeIDs.Length;
            var bones     = new List <PmxBone>(boneCount);

            var hierachy = BoneUtils.BuildBoneHierarchy(combinedAvatar);

            for (var i = 0; i < boneCount; ++i)
            {
                var bone      = new PmxBone();
                var transform = combinedAvatar.AvatarSkeletonPose.Transforms[i];
                var boneNode  = hierachy[i];

                var pmxBoneName = BoneUtils.GetPmxBoneName(boneNode.Path);

                bone.Name        = pmxBoneName;
                bone.NameEnglish = BoneUtils.TranslateBoneName(pmxBoneName);

                // PMX's bone positions are in world coordinate system.
                // Unity's are in local coords.
                bone.InitialPosition = boneNode.InitialPositionWorld;
                bone.CurrentPosition = bone.InitialPosition;

                bone.ParentIndex = boneNode.Parent?.Index ?? -1;
                bone.BoneIndex   = i;

                var singleDirectChild = GetDirectSingleChildOf(boneNode);

                if (singleDirectChild != null)
                {
                    bone.SetFlag(BoneFlags.ToBone);
                    bone.To_Bone = singleDirectChild.Index;
                }
                else
                {
                    // TODO: Fix this; it should point to a world position.
                    bone.To_Offset = transform.Translation.ToOpenTK().FixUnityToOpenTK();
                }

                // No use. This is just a flag to specify more details to rotation/translation limitation.
                //bone.SetFlag(BoneFlags.LocalFrame);
                bone.InitialRotation = transform.Rotation.ToOpenTK().FixUnityToOpenTK();
                bone.CurrentRotation = bone.InitialRotation;

                //bone.Level = boneNode.Level;
                bone.Level = 0;

                if (BoneUtils.IsBoneMovable(boneNode.Path))
                {
                    bone.SetFlag(BoneFlags.Rotation | BoneFlags.Translation);
                }
                else
                {
                    bone.SetFlag(BoneFlags.Rotation);
                }

                if (ConversionConfig.Current.HideUnityGeneratedBones)
                {
                    if (BoneUtils.IsNameGenerated(boneNode.Path))
                    {
                        bone.ClearFlag(BoneFlags.Visible);
                    }
                }

                bones.Add(bone);
            }

            if (ConversionConfig.Current.FixMmdCenterBones)
            {
                // Add master (全ての親) and center (センター), recompute bone hierarchy.
                PmxBone master = new PmxBone(), center = new PmxBone();

                master.Name        = "全ての親";
                master.NameEnglish = "master";
                center.Name        = "センター";
                center.NameEnglish = "center";

                master.ParentIndex = 0; // "" bone
                center.ParentIndex = 1; // "master" bone

                master.CurrentPosition = master.InitialPosition = Vector3.Zero;
                center.CurrentPosition = center.InitialPosition = Vector3.Zero;

                master.SetFlag(BoneFlags.Translation | BoneFlags.Rotation);
                center.SetFlag(BoneFlags.Translation | BoneFlags.Rotation);

                bones.Insert(1, master);
                bones.Insert(2, center);

                //// Fix "MODEL_00" bone

                //do {
                //    var model00 = bones.Find(b => b.Name == "グルーブ");

                //    if (model00 == null) {
                //        throw new ArgumentException("MODEL_00 mapped bone is not found.");
                //    }

                //    model00.ParentIndex = 2; // "center" bone
                //} while (false);

                const int numBonesAdded = 2;

                // Fix vertices and other bones
                foreach (var vertex in vertices)
                {
                    foreach (var boneWeight in vertex.BoneWeights)
                    {
                        if (boneWeight.BoneIndex == 0 && boneWeight.Weight <= 0)
                        {
                            continue;
                        }

                        if (boneWeight.BoneIndex >= 1)
                        {
                            boneWeight.BoneIndex += numBonesAdded;
                        }
                    }
                }

                for (var i = numBonesAdded + 1; i < bones.Count; ++i)
                {
                    var bone = bones[i];

                    bone.ParentIndex += numBonesAdded;

                    if (bone.HasFlag(BoneFlags.ToBone))
                    {
                        bone.To_Bone += numBonesAdded;
                    }
                }
            }

            if (ConversionConfig.Current.AppendIKBones)
            {
                // Add IK bones.

                PmxBone[] CreateLegIK(string leftRightJp, string leftRightEn)
                {
                    var startBoneCount = bones.Count;

                    PmxBone ikParent = new PmxBone(), ikBone = new PmxBone();

                    ikParent.Name        = leftRightJp + "足IK親";
                    ikParent.NameEnglish = "leg IKP_" + leftRightEn;
                    ikBone.Name          = leftRightJp + "足IK";
                    ikBone.NameEnglish   = "leg IK_" + leftRightEn;

                    PmxBone master;

                    do
                    {
                        master = bones.Find(b => b.Name == "全ての親");

                        if (master == null)
                        {
                            throw new ArgumentException("Missing master bone.");
                        }
                    } while (false);

                    ikParent.ParentIndex = bones.IndexOf(master);
                    ikBone.ParentIndex   = startBoneCount; // IKP
                    ikParent.SetFlag(BoneFlags.ToBone);
                    ikBone.SetFlag(BoneFlags.ToBone);
                    ikParent.To_Bone = startBoneCount + 1; // IK
                    ikBone.To_Bone   = -1;

                    PmxBone ankle, knee, leg;

                    do
                    {
                        var ankleName = leftRightJp + "足首";
                        ankle = bones.Find(b => b.Name == ankleName);
                        var kneeName = leftRightJp + "ひざ";
                        knee = bones.Find(b => b.Name == kneeName);
                        var legName = leftRightJp + "足";
                        leg = bones.Find(b => b.Name == legName);

                        if (ankle == null)
                        {
                            throw new ArgumentException("Missing ankle bone.");
                        }

                        if (knee == null)
                        {
                            throw new ArgumentException("Missing knee bone.");
                        }

                        if (leg == null)
                        {
                            throw new ArgumentException("Missing leg bone.");
                        }
                    } while (false);

                    ikBone.CurrentPosition   = ikBone.InitialPosition = ankle.InitialPosition;
                    ikParent.CurrentPosition = ikParent.InitialPosition = new Vector3(ikBone.InitialPosition.X, 0, ikBone.InitialPosition.Z);

                    ikParent.SetFlag(BoneFlags.Translation | BoneFlags.Rotation);
                    ikBone.SetFlag(BoneFlags.Translation | BoneFlags.Rotation | BoneFlags.IK);

                    var ik = new PmxIK();

                    ik.LoopCount       = 10;
                    ik.AngleLimit      = MathHelper.DegreesToRadians(114.5916f);
                    ik.TargetBoneIndex = bones.IndexOf(ankle);

                    var links = new IKLink[2];

                    links[0]            = new IKLink();
                    links[0].BoneIndex  = bones.IndexOf(knee);
                    links[0].IsLimited  = true;
                    links[0].LowerBound = new Vector3(MathHelper.DegreesToRadians(-180), 0, 0);
                    links[0].UpperBound = new Vector3(MathHelper.DegreesToRadians(-0.5f), 0, 0);
                    links[1]            = new IKLink();
                    links[1].BoneIndex  = bones.IndexOf(leg);

                    ik.Links  = links;
                    ikBone.IK = ik;

                    return(new[] {
                        ikParent, ikBone
                    });
                }

                PmxBone[] CreateToeIK(string leftRightJp, string leftRightEn)
                {
                    PmxBone ikParent, ikBone = new PmxBone();

                    do
                    {
                        var parentName = leftRightJp + "足IK";

                        ikParent = bones.Find(b => b.Name == parentName);

                        Debug.Assert(ikParent != null, nameof(ikParent) + " != null");
                    } while (false);

                    ikBone.Name        = leftRightJp + "つま先IK";
                    ikBone.NameEnglish = "toe IK_" + leftRightEn;

                    ikBone.ParentIndex = bones.IndexOf(ikParent);

                    ikBone.SetFlag(BoneFlags.ToBone);
                    ikBone.To_Bone = -1;

                    PmxBone toe, ankle;

                    do
                    {
                        var toeName = leftRightJp + "つま先";
                        toe = bones.Find(b => b.Name == toeName);
                        var ankleName = leftRightJp + "足首";
                        ankle = bones.Find(b => b.Name == ankleName);

                        if (toe == null)
                        {
                            throw new ArgumentException("Missing toe bone.");
                        }

                        if (ankle == null)
                        {
                            throw new ArgumentException("Missing ankle bone.");
                        }
                    } while (false);

                    ikBone.CurrentPosition = ikBone.InitialPosition = toe.InitialPosition;
                    ikBone.SetFlag(BoneFlags.Translation | BoneFlags.Rotation | BoneFlags.IK);

                    var ik = new PmxIK();

                    ik.LoopCount       = 10;
                    ik.AngleLimit      = MathHelper.DegreesToRadians(114.5916f);
                    ik.TargetBoneIndex = bones.IndexOf(toe);

                    var links = new IKLink[1];

                    links[0]           = new IKLink();
                    links[0].BoneIndex = bones.IndexOf(ankle);

                    ik.Links  = links.ToArray();
                    ikBone.IK = ik;

                    return(new[] {
                        ikBone
                    });
                }

                var leftLegIK = CreateLegIK("左", "L");
                bones.AddRange(leftLegIK);
                var rightLegIK = CreateLegIK("右", "R");
                bones.AddRange(rightLegIK);

                var leftToeIK = CreateToeIK("左", "L");
                bones.AddRange(leftToeIK);
                var rightToeIK = CreateToeIK("右", "R");
                bones.AddRange(rightToeIK);
            }

            if (ConversionConfig.Current.AppendEyeBones)
            {
                (int VertexStart1, int VertexCount1, int VertexStart2, int VertexCount2) FindEyesVerticeRange()
                {
                    var meshNameIndex = -1;
                    var cm            = combinedMesh as CompositeMesh;

                    Debug.Assert(cm != null, nameof(cm) + " != null");

                    for (var i = 0; i < cm.Names.Count; i++)
                    {
                        var meshName = cm.Names[i];

                        if (meshName == "eyes")
                        {
                            meshNameIndex = i;
                            break;
                        }
                    }

                    if (meshNameIndex < 0)
                    {
                        throw new ArgumentException("Mesh \"eyes\" is missing.");
                    }

                    var subMeshMaps = cm.ParentMeshIndices.Enumerate().Where(s => s.Value == meshNameIndex).ToArray();

                    Debug.Assert(subMeshMaps.Length == 2, "There should be 2 sub mesh maps.");
                    Debug.Assert(subMeshMaps[1].Index - subMeshMaps[0].Index == 1, "The first sub mesh map should contain one element.");

                    var vertexStart1 = (int)cm.SubMeshes[subMeshMaps[0].Index].FirstVertex;
                    var vertexCount1 = (int)cm.SubMeshes[subMeshMaps[0].Index].VertexCount;
                    var vertexStart2 = (int)cm.SubMeshes[subMeshMaps[1].Index].FirstVertex;
                    var vertexCount2 = (int)cm.SubMeshes[subMeshMaps[1].Index].VertexCount;

                    return(vertexStart1, vertexCount1, vertexStart2, vertexCount2);
                }

                Vector3 GetEyeBonePosition(int vertexStart, int vertexCount)
                {
                    var centerPos = Vector3.Zero;
                    var leftMostPos = new Vector3(float.MinValue, 0, 0);
                    var rightMostPos = new Vector3(float.MaxValue, 0, 0);
                    int leftMostIndex = -1, rightMostIndex = -1;

                    for (var i = vertexStart; i < vertexStart + vertexCount; ++i)
                    {
                        var pos = vertices[i].Position;

                        centerPos += pos;

                        if (pos.X > leftMostPos.X)
                        {
                            leftMostPos   = pos;
                            leftMostIndex = i;
                        }

                        if (pos.X < rightMostPos.X)
                        {
                            rightMostPos   = pos;
                            rightMostIndex = i;
                        }
                    }

                    Debug.Assert(leftMostIndex >= 0, nameof(leftMostIndex) + " >= 0");
                    Debug.Assert(rightMostIndex >= 0, nameof(rightMostIndex) + " >= 0");

                    centerPos = centerPos / vertexCount;

                    // "Eyeball". You got the idea?
                    var leftMostNorm  = vertices[leftMostIndex].Normal;
                    var rightMostNorm = vertices[rightMostIndex].Normal;

                    var   k1 = leftMostNorm.Z / leftMostNorm.X;
                    var   k2 = rightMostNorm.Z / rightMostNorm.X;
                    float x1 = leftMostPos.X, x2 = rightMostPos.X, z1 = leftMostPos.Z, z2 = rightMostPos.Z;

                    var d1 = (z2 - k2 * x2 + k2 * x1 - z1) / (k1 - k2);

                    var x = x1 + d1;
                    var z = z1 + k1 * d1;

                    return(new Vector3(x, centerPos.Y, z));
                }

                Vector3 GetEyesBonePosition(int vertexStart1, int vertexCount1, int vertexStart2, int vertexCount2)
                {
                    var result = new Vector3();

                    for (var i = vertexStart1; i < vertexStart1 + vertexCount1; ++i)
                    {
                        result += vertices[i].Position;
                    }
                    for (var i = vertexStart2; i < vertexStart2 + vertexCount2; ++i)
                    {
                        result += vertices[i].Position;
                    }

                    result = result / (vertexCount1 + vertexCount2);

                    return(new Vector3(0, result.Y + 0.5f, -0.6f));
                }

                var(vs1, vc1, vs2, vc2) = FindEyesVerticeRange();
                PmxBone head;

                do
                {
                    head = bones.Find(b => b.Name == "頭");

                    if (head == null)
                    {
                        throw new ArgumentException("Missing head bone.");
                    }
                } while (false);

                var eyes = new PmxBone();

                eyes.Name        = "両目";
                eyes.NameEnglish = "eyes";

                eyes.Parent      = head;
                eyes.ParentIndex = bones.IndexOf(head);

                eyes.CurrentPosition = eyes.InitialPosition = GetEyesBonePosition(vs1, vc1, vs2, vc2);

                eyes.SetFlag(BoneFlags.Visible | BoneFlags.Rotation | BoneFlags.ToBone);
                eyes.To_Bone = -1;

                bones.Add(eyes);

                PmxBone leftEye = new PmxBone(), rightEye = new PmxBone();

                leftEye.Name         = "左目";
                leftEye.NameEnglish  = "eye_L";
                rightEye.Name        = "右目";
                rightEye.NameEnglish = "eye_R";

                leftEye.Parent       = head;
                leftEye.ParentIndex  = bones.IndexOf(head);
                rightEye.Parent      = head;
                rightEye.ParentIndex = bones.IndexOf(head);

                leftEye.SetFlag(BoneFlags.Visible | BoneFlags.Rotation | BoneFlags.ToBone | BoneFlags.AppendRotation);
                rightEye.SetFlag(BoneFlags.Visible | BoneFlags.Rotation | BoneFlags.ToBone | BoneFlags.AppendRotation);
                leftEye.To_Bone            = -1;
                rightEye.To_Bone           = -1;
                leftEye.AppendParent       = eyes;
                rightEye.AppendParent      = eyes;
                leftEye.AppendParentIndex  = bones.IndexOf(eyes);
                rightEye.AppendParentIndex = bones.IndexOf(eyes);
                leftEye.AppendRatio        = 1;
                rightEye.AppendRatio       = 1;

                leftEye.CurrentPosition  = leftEye.InitialPosition = GetEyeBonePosition(vs1, vc1);
                rightEye.CurrentPosition = rightEye.InitialPosition = GetEyeBonePosition(vs2, vc2);

                bones.Add(leftEye);
                bones.Add(rightEye);

                // Fix vertices
                {
                    var leftEyeIndex  = bones.IndexOf(leftEye);
                    var rightEyeIndex = bones.IndexOf(rightEye);

                    for (var i = vs1; i < vs1 + vc1; ++i)
                    {
                        var skin = vertices[i];
                        // Eyes are only affected by "KUBI/ATAMA" bone by default. So we only need to set one element's values.
                        skin.BoneWeights[0].BoneIndex = leftEyeIndex;
                        Debug.Assert(Math.Abs(skin.BoneWeights[0].Weight - 1) < 0.000001f, "Total weight in the skin of left eye should be 1.");
                    }
                    for (var i = vs2; i < vs2 + vc2; ++i)
                    {
                        var skin = vertices[i];
                        // Eyes are only affected by "KUBI/ATAMA" bone by default. So we only need to set one element's values.
                        skin.BoneWeights[0].BoneIndex = rightEyeIndex;
                        Debug.Assert(Math.Abs(skin.BoneWeights[0].Weight - 1) < 0.000001f, "Total weight in the skin of right eye should be 1.");
                    }
                }
            }

            // Finally, set the indices. The values will be used later.
            for (var i = 0; i < bones.Count; i++)
            {
                bones[i].BoneIndex = i;
            }

            return(bones.ToArray());
        }
Exemple #19
0
 public EntityBone(World world, PmxBone bone, Bone mmmBone) : base(world)
 {
     PmxBone = bone;
     MMMBone = mmmBone;
 }
Exemple #20
0
        private PmxModel ReadPmxModel()
        {
            var model = new PmxModel();

            model.Name           = ReadString() ?? string.Empty;
            model.NameEnglish    = ReadString() ?? string.Empty;
            model.Comment        = ReadString() ?? string.Empty;
            model.CommentEnglish = ReadString() ?? string.Empty;

            ReadVertexInfo();
            ReadFaceInfo();
            ReadTextureInfo();
            ReadMaterialInfo();
            ReadBoneInfo();
            ReadMorphInfo();
            ReadNodeInfo();
            ReadRigidBodyInfo();
            ReadJointInfo();
            ReadSoftBodyInfo();

            return(model);

            void ReadVertexInfo()
            {
                var vertexCount = _reader.ReadInt32();
                var vertices    = new PmxVertex[vertexCount];

                for (var i = 0; i < vertexCount; ++i)
                {
                    vertices[i] = ReadPmxVertex();
                }

                model.Vertices = vertices;
            }

            void ReadFaceInfo()
            {
                var faceCount   = _reader.ReadInt32();
                var faceIndices = new int[faceCount];

                for (var i = 0; i < faceCount; ++i)
                {
                    faceIndices[i] = _reader.ReadVarLenIntAsInt32(VertexElementSize, true);
                }

                model.FaceTriangles = faceIndices;
            }

            void ReadTextureInfo()
            {
                var textureCount       = _reader.ReadInt32();
                var textureNameMap     = new Dictionary <int, string>();
                var textureIndexLookup = new Dictionary <string, int>();

                for (var i = 0; i < textureCount; ++i)
                {
                    var textureName = ReadString() ?? string.Empty;
                    textureNameMap[i] = textureName;
                    textureIndexLookup[textureName] = i;
                }

                textureNameMap[-1] = string.Empty;

                TextureNameMap     = textureNameMap;
                TextureIndexLookup = textureIndexLookup;
            }

            void ReadMaterialInfo()
            {
                var materialCount = _reader.ReadInt32();
                var materials     = new PmxMaterial[materialCount];

                for (var i = 0; i < materialCount; ++i)
                {
                    materials[i] = ReadPmxMaterial();
                }

                model.Materials = materials;
            }

            void ReadBoneInfo()
            {
                var boneCount = _reader.ReadInt32();
                var bones     = new PmxBone[boneCount];

                for (var i = 0; i < boneCount; ++i)
                {
                    bones[i]           = ReadPmxBone();
                    bones[i].BoneIndex = i;
                }

                model.Bones           = bones;
                model.BonesDictionary = bones.ToDictionary(bone => bone.Name);

                var rootBoneIndexList = new List <int>();

                for (var i = 0; i < bones.Length; ++i)
                {
                    var bone = bones[i];

                    if (bone.ParentIndex < 0)
                    {
                        rootBoneIndexList.Add(i);
                    }
                    else
                    {
                        bone.Parent = bones[bone.ParentIndex];
                    }

                    if (bone.AppendParentIndex >= 0)
                    {
                        bone.AppendParent = bones[bone.AppendParentIndex];
                    }

                    if (bone.ExternalParentIndex >= 0)
                    {
                        bone.ExternalParent = bones[bone.ExternalParentIndex];
                    }

                    if (bone.HasFlag(BoneFlags.IK))
                    {
                        var ik = bone.IK;

                        Debug.Assert(ik != null, nameof(ik) + " != null");

                        ik.TargetBone = bones[ik.TargetBoneIndex];

                        foreach (var link in ik.Links)
                        {
                            if (link.BoneIndex >= 0)
                            {
                                link.Bone = bones[link.BoneIndex];
                            }
                        }
                    }
                }

                model.RootBoneIndices = rootBoneIndexList.ToArray();

                foreach (var bone in bones)
                {
                    bone.SetToBindingPose();
                }
            }

            void ReadMorphInfo()
            {
                var morphCount = _reader.ReadInt32();
                var morphs     = new PmxMorph[morphCount];

                for (var i = 0; i < morphCount; ++i)
                {
                    morphs[i] = ReadPmxMorph();
                }

                model.Morphs = morphs;
            }

            void ReadNodeInfo()
            {
                var nodeCount = _reader.ReadInt32();
                var nodes     = new PmxNode[nodeCount];

                for (var i = 0; i < nodeCount; ++i)
                {
                    var node = ReadPmxNode();

                    nodes[i] = node;

                    if (node.IsSystemNode)
                    {
                        if (node.Name == "Root")
                        {
                            model.RootNodeIndex = i;
                        }
                        else if (node.Name == "表情")
                        {
                            model.FacialExpressionNodeIndex = i;
                        }
                    }
                }

                model.Nodes = nodes;
            }

            void ReadRigidBodyInfo()
            {
                var bodyCount = _reader.ReadInt32();
                var bodies    = new PmxRigidBody[bodyCount];

                for (var i = 0; i < bodyCount; ++i)
                {
                    bodies[i] = ReadPmxRigidBody();
                }

                model.RigidBodies = bodies;
            }

            void ReadJointInfo()
            {
                var jointCount = _reader.ReadInt32();
                var joints     = new PmxJoint[jointCount];

                for (var i = 0; i < jointCount; ++i)
                {
                    joints[i] = ReadPmxJoint();
                }

                model.Joints = joints;
            }

            void ReadSoftBodyInfo()
            {
                if (DetailedVersion < 2.1f)
                {
                    return;
                }

                var bodyCount = _reader.ReadInt32();
                var bodies    = new PmxSoftBody[bodyCount];

                for (var i = 0; i < bodyCount; ++i)
                {
                    bodies[i] = ReadPmxSoftBody();
                }

                model.SoftBodies = bodies;
            }
        }
        // PMDEditor.Pmx
        internal static Pmx FromStream(Stream s, PmxElementFormat f = null)
        {
            var Ret       = new Pmx();
            var pmxHeader = new PmxHeader(2f);

            pmxHeader.FromStreamEx(s, null);
            Ret.Header = pmxHeader;
            if (pmxHeader.Ver <= 1f)
            {
                var mMD_Pmd = new MMD_Pmd();
                s.Seek(0L, SeekOrigin.Begin);
                mMD_Pmd.FromStreamEx(s, null);
                Ret.FromPmx(PmxConvert.PmdToPmx(mMD_Pmd));
                return(Ret);
            }
            Ret.ModelInfo = new PmxModelInfo();
            Ret.ModelInfo.FromStreamEx(s, pmxHeader.ElementFormat);
            var num = PmxStreamHelper.ReadElement_Int32(s, 4, true);

            Ret.VertexList = new List <PmxVertex>();
            Ret.VertexList.Clear();
            Ret.VertexList.Capacity = num;
            for (var i = 0; i < num; i++)
            {
                var pmxVertex = new PmxVertex();
                pmxVertex.FromStreamEx(s, pmxHeader.ElementFormat);
                Ret.VertexList.Add(pmxVertex);
            }
            num          = PmxStreamHelper.ReadElement_Int32(s, 4, true);
            Ret.FaceList = new List <int>();
            Ret.FaceList.Clear();
            Ret.FaceList.Capacity = num;
            for (var j = 0; j < num; j++)
            {
                var item = PmxStreamHelper.ReadElement_Int32(s, pmxHeader.ElementFormat.VertexSize, false);
                Ret.FaceList.Add(item);
            }
            var pmxTextureTable = new PmxTextureTable();

            pmxTextureTable.FromStreamEx(s, pmxHeader.ElementFormat);
            num = PmxStreamHelper.ReadElement_Int32(s, 4, true);
            Ret.MaterialList = new List <PmxMaterial>();
            Ret.MaterialList.Clear();
            Ret.MaterialList.Capacity = num;
            for (var k = 0; k < num; k++)
            {
                var pmxMaterial = new PmxMaterial();
                pmxMaterial.FromStreamEx_TexTable(s, pmxTextureTable, pmxHeader.ElementFormat);
                Ret.MaterialList.Add(pmxMaterial);
            }
            num          = PmxStreamHelper.ReadElement_Int32(s, 4, true);
            Ret.BoneList = new List <PmxBone>();
            Ret.BoneList.Clear();
            Ret.BoneList.Capacity = num;

            for (var l = 0; l < num; l++)
            {
                var pmxBone = new PmxBone();
                pmxBone.FromStreamEx(s, pmxHeader.ElementFormat);
                Ret.BoneList.Add(pmxBone);
            }
            num           = PmxStreamHelper.ReadElement_Int32(s, 4, true);
            Ret.MorphList = new List <PmxMorph>();
            Ret.MorphList.Clear();
            Ret.MorphList.Capacity = num;
            for (var m = 0; m < num; m++)
            {
                var pmxMorph = new PmxMorph();
                pmxMorph.FromStreamEx(s, pmxHeader.ElementFormat);
                Ret.MorphList.Add(pmxMorph);
            }
            num          = PmxStreamHelper.ReadElement_Int32(s, 4, true);
            Ret.NodeList = new List <PmxNode>();
            Ret.NodeList.Clear();
            Ret.NodeList.Capacity = num;
            for (var n = 0; n < num; n++)
            {
                var pmxNode = new PmxNode();
                pmxNode.FromStreamEx(s, pmxHeader.ElementFormat);
                Ret.NodeList.Add(pmxNode);
                if (Ret.NodeList[n].SystemNode)
                {
                    if (Ret.NodeList[n].Name == "Root")
                    {
                        Ret.RootNode = Ret.NodeList[n];
                    }
                    else if (Ret.NodeList[n].Name == "表情")
                    {
                        Ret.ExpNode = Ret.NodeList[n];
                    }
                }
            }
            num          = PmxStreamHelper.ReadElement_Int32(s, 4, true);
            Ret.BodyList = new List <PmxBody>();
            Ret.BodyList.Clear();
            Ret.BodyList.Capacity = num;
            for (var num2 = 0; num2 < num; num2++)
            {
                var pmxBody = new PmxBody();
                pmxBody.FromStreamEx(s, pmxHeader.ElementFormat);
                Ret.BodyList.Add(pmxBody);
            }
            num           = PmxStreamHelper.ReadElement_Int32(s, 4, true);
            Ret.JointList = new List <PmxJoint>();
            Ret.JointList.Clear();
            Ret.JointList.Capacity = num;
            for (var num3 = 0; num3 < num; num3++)
            {
                var pmxJoint = new PmxJoint();
                pmxJoint.FromStreamEx(s, pmxHeader.ElementFormat);
                Ret.JointList.Add(pmxJoint);
            }
            return(Ret);
        }