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); } } } }
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); }
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); }
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; } }
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()); }
// 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); }