private void CreateMorphs(TBodySkin skin)
        {
            if (skin == null || skin.morph == null || skin.morph.BlendDatas.Count <= 0)
            {
                return;
            }
            if (!vertexIndexMap.ContainsKey(skin.obj.name))
            {
                Debug.Log($"Morph: {skin.obj.name} -> Missing vertex base!");
                return;
            }
            int vertexBase = vertexIndexMap[skin.obj.name];

            Debug.Log($"Morph: {skin.obj.name} -> {skin.morph.BlendDatas.Count} ({vertexBase})");
            for (int j = 0; j < skin.morph.BlendDatas.Count; j++)
            {
                BlendData blendData = skin.morph.BlendDatas[j];
                if (blendData != null)
                {
                    PmxMorph pmxMorph = GetOrCreateMorph(blendData.name);
                    for (int k = 0; k < blendData.v_index.Length; k++)
                    {
                        PmxVertexMorph pmxVertexMorph = new PmxVertexMorph(blendData.v_index[k] + vertexBase, new PmxLib.Vector3(-blendData.vert[k].x, blendData.vert[k].z, blendData.vert[k].y));
                        pmxVertexMorph.Offset *= scaleFactor;
                        pmxMorph.OffsetList.Add(pmxVertexMorph);
                    }
                }
            }
        }
Example #2
0
        private PmxMorph ReadPmxMorph()
        {
            var morph = new PmxMorph();

            morph.Name        = ReadString() ?? string.Empty;
            morph.NameEnglish = ReadString() ?? string.Empty;
            morph.Panel       = _reader.ReadSByte();                 // TODO: Signed? Unsigned?
            morph.OffsetKind  = (MorphOffsetKind)_reader.ReadByte(); // TODO: Signed? Unsigned?

            var morphCount = _reader.ReadInt32();
            var morphs     = new List <PmxBaseMorph>();

            for (var i = 0; i < morphCount; ++i)
            {
                PmxBaseMorph baseMorph;

                switch (morph.OffsetKind)
                {
                case MorphOffsetKind.Group:
                case MorphOffsetKind.Flip:
                    baseMorph = ReadPmxGroupMorph();
                    break;

                case MorphOffsetKind.Vertex:
                    baseMorph = ReadPmxVertexMorph();
                    break;

                case MorphOffsetKind.Bone:
                    baseMorph = ReadPmxBoneMorph();
                    break;

                case MorphOffsetKind.UV:
                case MorphOffsetKind.Uva1:
                case MorphOffsetKind.Uva2:
                case MorphOffsetKind.Uva3:
                case MorphOffsetKind.Uva4:
                    baseMorph = ReadPmxUVMorph();
                    break;

                case MorphOffsetKind.Material:
                    baseMorph = ReadPmxMaterialMorph();
                    break;

                case MorphOffsetKind.Impulse:
                    baseMorph = ReadPmxImpulseMorph();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                morphs.Add(baseMorph);
            }

            morph.Offsets = morphs.ToArray();

            return(morph);
        }
Example #3
0
        private void WritePmxMorph([NotNull] PmxMorph morph)
        {
            WriteString(morph.Name);
            WriteString(morph.NameEnglish);

            _writer.Write((sbyte)morph.Panel);
            _writer.Write((byte)morph.OffsetKind);

            if (morph.Offsets != null)
            {
                _writer.Write(morph.Offsets.Count);

                foreach (var subm in morph.Offsets)
                {
                    switch (subm)
                    {
                    case PmxGroupMorph m0:
                        WritePmxGroupMorph(m0);
                        break;

                    case PmxVertexMorph m1:
                        WritePmxVertexMorph(m1);
                        break;

                    case PmxBoneMorph m2:
                        WritePmxBoneMorph(m2);
                        break;

                    case PmxUVMorph m3:
                        WritePmxUVMorph(m3);
                        break;

                    case PmxMaterialMorph m4:
                        WritePmxMaterialMorph(m4);
                        break;

                    case PmxImpulseMorph m5:
                        WritePmxImpulseMorph(m5);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            }
            else
            {
                _writer.Write(0);
            }
        }
        private PmxMorph GetOrCreateMorph(string name)
        {
            if (morphMap.ContainsKey(name))
            {
                return(morphMap[name]);
            }
            PmxMorph pmxMorph = new PmxMorph();

            pmxMorph.Name  = name;
            pmxMorph.NameE = name;
            pmxMorph.Panel = 1;
            pmxMorph.Kind  = PmxMorph.OffsetKind.Vertex;
            pmxFile.MorphList.Add(pmxMorph);
            morphMap.Add(name, pmxMorph);
            return(pmxMorph);
        }
Example #5
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;
            }
        }
Example #6
0
        private static IReadOnlyList <PmxMorph> AddEmotionMorphs([NotNull] Mesh mesh)
        {
            var morphs = new List <PmxMorph>();

            var s = mesh.Shape;

            if (s != null)
            {
                Debug.Assert(s.Channels.Count == s.Shapes.Count, "s.Channels.Count == s.Shapes.Count");
                Debug.Assert(s.Channels.Count == s.FullWeights.Count, "s.Channels.Count == s.FullWeights.Count");

                var morphCount = s.Channels.Count;

                for (var i = 0; i < morphCount; i++)
                {
                    var channel  = s.Channels[i];
                    var shape    = s.Shapes[i];
                    var vertices = s.Vertices;
                    var morph    = new PmxMorph();

                    var morphName = channel.Name.Substring(12); // - "blendShape1."

                    if (ConversionConfig.Current.TranslateFacialExpressionNamesToMmd)
                    {
                        morph.Name = MorphUtils.LookupMorphName(morphName);
                    }
                    else
                    {
                        morph.Name = morphName;
                    }

                    morph.NameEnglish = morphName;

                    morph.OffsetKind = MorphOffsetKind.Vertex;

                    var offsets = new List <PmxBaseMorph>();

                    for (var j = shape.FirstVertex; j < shape.FirstVertex + shape.VertexCount; ++j)
                    {
                        var v = vertices[(int)j];
                        var m = new PmxVertexMorph();

                        var offset = v.Vertex.ToOpenTK().FixUnityToOpenTK();

                        if (ConversionConfig.Current.ScaleToPmxSize)
                        {
                            offset = offset * ScalingConfig.ScaleUnityToPmx;
                        }

                        m.Index  = (int)v.Index;
                        m.Offset = offset;

                        offsets.Add(m);
                    }

                    morph.Offsets = offsets.ToArray();

                    morphs.Add(morph);
                }

                // Now some custom morphs for our model to be compatible with TDA.
                do
                {
                    PmxMorph CreateCompositeMorph(string mltdTruncMorphName, params string[] truncNames)
                    {
                        int FindIndex <T>(IReadOnlyList <T> list, T item)
                        {
                            var comparer = EqualityComparer <T> .Default;

                            for (var i = 0; i < list.Count; ++i)
                            {
                                if (comparer.Equals(item, list[i]))
                                {
                                    return(i);
                                }
                            }

                            return(-1);
                        }

                        var morph = new PmxMorph();

                        if (ConversionConfig.Current.TranslateFacialExpressionNamesToMmd)
                        {
                            morph.Name = MorphUtils.LookupMorphName(mltdTruncMorphName);
                        }
                        else
                        {
                            morph.Name = mltdTruncMorphName;
                        }

                        morph.NameEnglish = mltdTruncMorphName;

                        var offsets  = new List <PmxBaseMorph>();
                        var vertices = s.Vertices;

                        foreach (var channel in truncNames.Select(name => {
                            // name: e.g. "E_metoji_l"
                            // ch_ex005_016tsu has "blendShape2.E_metoji_l" instead of the common one "blendShape1.E_metoji_l"
                            // so the old method (string equal to full name) breaks.
                            var chan = s.Channels.SingleOrDefault(ch => ch.Name.EndsWith(name));

                            if (chan == null)
                            {
                                Trace.WriteLine($"Warning: required blend channel not found: {name}");
                            }

                            return(chan);
                        }))
                        {
                            if (channel == null)
                            {
                                continue;
                            }

                            var channelIndex = FindIndex(s.Channels, channel);
                            var shape        = s.Shapes[channelIndex];

                            morph.OffsetKind = MorphOffsetKind.Vertex;

                            for (var j = shape.FirstVertex; j < shape.FirstVertex + shape.VertexCount; ++j)
                            {
                                var v = vertices[(int)j];
                                var m = new PmxVertexMorph();

                                var offset = v.Vertex.ToOpenTK().FixUnityToOpenTK();

                                if (ConversionConfig.Current.ScaleToPmxSize)
                                {
                                    offset = offset * ScalingConfig.ScaleUnityToPmx;
                                }

                                m.Index  = (int)v.Index;
                                m.Offset = offset;

                                offsets.Add(m);
                            }
                        }

                        morph.Offsets = offsets.ToArray();

                        return(morph);
                    }

                    morphs.Add(CreateCompositeMorph("E_metoji", "E_metoji_l", "E_metoji_r"));
                } while (false);
            }

            return(morphs.ToArray());
        }
Example #7
0
        // 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);
        }