Skip to content

Instantly share code, notes, and snippets.

@yomotsu
Created November 26, 2018 16:41
Show Gist options
  • Save yomotsu/2242a902edf1b146bfffe319912aa779 to your computer and use it in GitHub Desktop.
Save yomotsu/2242a902edf1b146bfffe319912aa779 to your computer and use it in GitHub Desktop.
using UnityEngine;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using MMDataIO.Pmx;
using System.IO;
using VRM;
#if UNITY_EDITOR
using UnityEditor;
#endif
[ExecuteInEditMode]
public class PMXExporter : MonoBehaviour
{
public bool ReplaceBoneName = true;
public bool ConvertArmatuar_NeedReplaceBoneName = true;
public bool ReplaceMorphName = true;
#if UNITY_EDITOR
[ContextMenu("Export")]
void Init()
{
Debug.Log("build 170");
bool ConvertArmatuar = ReplaceBoneName && ConvertArmatuar_NeedReplaceBoneName;
Quaternion? tmpRootRot = null;
Quaternion? tmpLUARot = null;
Quaternion? tmpRUARot = null;
float caScaling = 10.0f;
try
{
if (ConvertArmatuar)
{
var anim = GetComponent<Animator>();
var lua = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm);
tmpLUARot = lua.rotation;
lua.Rotate(new Vector3(0, 0, 30));
var rua = anim.GetBoneTransform(HumanBodyBones.RightUpperArm);
tmpRUARot = rua.rotation;
rua.Rotate(new Vector3(0, 0, -30));
tmpRootRot = transform.rotation;
transform.Rotate(new Vector3(0, 180, 0));
transform.localScale *= caScaling;
}
var filterdFileName = System.IO.Path.GetInvalidFileNameChars().Aggregate(
name, (s, c) => s.Replace(c.ToString(), ""));
string savepath = EditorUtility.SaveFilePanel("Export PMX", "", filterdFileName, "pmx");
if (string.IsNullOrEmpty(savepath))
{
Debug.Log("SavePath not exists.");
return;
}
var pmx = new PmxModelData();
using (FileStream fs = new FileStream("Assets/PMXExporter/vanilla.pmx", FileMode.Open))
using (BinaryReader br = new BinaryReader(fs))
{
pmx.Read(br);
}
Debug.Log("Load vanilla.pmx");
var ikTemplate = new PmxModelData();
using (FileStream fs = new FileStream("Assets/PMXExporter/iktemplate.pmx", FileMode.Open))
using (BinaryReader br = new BinaryReader(fs))
{
ikTemplate.Read(br);
}
Debug.Log("Load iktemplate.pmx");
var slots = new List<PmxSlotData>();
#region build_bone
{//bone
var humanoid2mmd = new SortedDictionary<HumanBodyBones, string>();
{
humanoid2mmd.Add(HumanBodyBones.Hips, "下半身");
humanoid2mmd.Add(HumanBodyBones.Spine, "上半身");
humanoid2mmd.Add(HumanBodyBones.Chest, "上半身2");
humanoid2mmd.Add(HumanBodyBones.LeftUpperLeg, "左足");
humanoid2mmd.Add(HumanBodyBones.LeftLowerLeg, "左ひざ");
humanoid2mmd.Add(HumanBodyBones.LeftFoot, "左足首");
humanoid2mmd.Add(HumanBodyBones.LeftToes, "左つま先");
humanoid2mmd.Add(HumanBodyBones.RightUpperLeg, "右足");
humanoid2mmd.Add(HumanBodyBones.RightLowerLeg, "右ひざ");
humanoid2mmd.Add(HumanBodyBones.RightFoot, "右足首");
humanoid2mmd.Add(HumanBodyBones.RightToes, "右つま先");
humanoid2mmd.Add(HumanBodyBones.Neck, "首");
humanoid2mmd.Add(HumanBodyBones.Head, "頭");
humanoid2mmd.Add(HumanBodyBones.LeftEye, "左目");
humanoid2mmd.Add(HumanBodyBones.RightEye, "右目");
humanoid2mmd.Add(HumanBodyBones.LeftShoulder, "左肩");
humanoid2mmd.Add(HumanBodyBones.LeftUpperArm, "左腕");
humanoid2mmd.Add(HumanBodyBones.LeftLowerArm, "左ひじ");
humanoid2mmd.Add(HumanBodyBones.LeftHand, "左手首");
humanoid2mmd.Add(HumanBodyBones.RightShoulder, "右肩");
humanoid2mmd.Add(HumanBodyBones.RightUpperArm, "右腕");
humanoid2mmd.Add(HumanBodyBones.RightLowerArm, "右ひじ");
humanoid2mmd.Add(HumanBodyBones.RightHand, "右手首");
humanoid2mmd.Add(HumanBodyBones.LeftRingProximal, "左薬指1");
humanoid2mmd.Add(HumanBodyBones.LeftRingIntermediate, "左薬指2");
humanoid2mmd.Add(HumanBodyBones.LeftRingDistal, "左薬指3");
humanoid2mmd.Add(HumanBodyBones.LeftThumbProximal, "左親指1");
humanoid2mmd.Add(HumanBodyBones.LeftThumbIntermediate, "左親指2");
humanoid2mmd.Add(HumanBodyBones.LeftIndexProximal, "左人指1");
humanoid2mmd.Add(HumanBodyBones.LeftIndexIntermediate, "左人指2");
humanoid2mmd.Add(HumanBodyBones.LeftIndexDistal, "左人指3");
humanoid2mmd.Add(HumanBodyBones.LeftMiddleProximal, "左中指1");
humanoid2mmd.Add(HumanBodyBones.LeftMiddleIntermediate, "左中指2");
humanoid2mmd.Add(HumanBodyBones.LeftMiddleDistal, "左中指3");
humanoid2mmd.Add(HumanBodyBones.LeftLittleProximal, "左小指1");
humanoid2mmd.Add(HumanBodyBones.LeftLittleIntermediate, "左小指2");
humanoid2mmd.Add(HumanBodyBones.LeftLittleDistal, "左小指3");
humanoid2mmd.Add(HumanBodyBones.RightRingProximal, "右薬指1");
humanoid2mmd.Add(HumanBodyBones.RightRingIntermediate, "右薬指2");
humanoid2mmd.Add(HumanBodyBones.RightRingDistal, "右薬指3");
humanoid2mmd.Add(HumanBodyBones.RightThumbProximal, "右親指1");
humanoid2mmd.Add(HumanBodyBones.RightThumbIntermediate, "右親指2");
humanoid2mmd.Add(HumanBodyBones.RightIndexProximal, "右人指1");
humanoid2mmd.Add(HumanBodyBones.RightIndexIntermediate, "右人指2");
humanoid2mmd.Add(HumanBodyBones.RightIndexDistal, "右人指3");
humanoid2mmd.Add(HumanBodyBones.RightMiddleProximal, "右中指1");
humanoid2mmd.Add(HumanBodyBones.RightMiddleIntermediate, "右中指2");
humanoid2mmd.Add(HumanBodyBones.RightMiddleDistal, "右中指3");
humanoid2mmd.Add(HumanBodyBones.RightLittleProximal, "右小指1");
humanoid2mmd.Add(HumanBodyBones.RightLittleIntermediate, "右小指2");
humanoid2mmd.Add(HumanBodyBones.RightLittleDistal, "右小指3");
}
var humanoidMapping = new SortedDictionary<string, HumanBodyBones>();
var humanoidDesc = GetComponent<VRM.VRMHumanoidDescription>();
foreach (var x in humanoidDesc.Description.human)
{
humanoidMapping.Add(x.boneName, x.humanBone);
}
System.Func<string, string> remapBoname = (orgName) =>
{
string remapName = orgName;
if (humanoidMapping.ContainsKey(orgName))
{
HumanBodyBones key = humanoidMapping[orgName];
if (humanoid2mmd.ContainsKey(key))
{
remapName = humanoid2mmd[key];
}
}
return remapName;
};
if (!ReplaceBoneName)
{
remapBoname = (orgName) => orgName;
}
var bones = new List<Transform>();
var boneStack = new Stack<Transform>();
boneStack.Push(transform);
while (0 < boneStack.Count)
{
var obj = boneStack.Pop();
bones.Add(obj);
foreach (Transform child in obj.transform)
{
boneStack.Push(child);
}
}
var indexedBones = bones.Select((b, idx) => new { id = idx, bone = b }).ToArray();
var create = indexedBones.Select(b => new PmxBoneData()
{
BoneName = remapBoname(b.bone.name),
BoneNameE = b.bone.name,
BoneId = b.id,
Pos = b.bone.position,
ParentId = b.bone.parent == null ? -1 : ((
indexedBones.Where(elm => elm.bone.name == b.bone.parent.name).FirstOrDefault()
?? indexedBones.First()
).id),
Flag = BoneFlags.VISIBLE | BoneFlags.ROTATE | BoneFlags.OP,
PosOffset = new Vector3(0, 0, ConvertArmatuar ? -0.5f : 0.1f),
});
pmx.BoneArray = create.ToArray();
if (ConvertArmatuar)
{
Debug.Log("ConvertArmatuar");
int centerId = -1;
var hips = pmx.BoneArray.Where(b => b.BoneName.Equals("下半身")).FirstOrDefault();
if (hips != null && 0 <= hips.ParentId && hips.ParentId < pmx.BoneArray.Length)
{
centerId = hips.ParentId;
var centerBone = pmx.BoneArray[centerId];
centerBone.BoneName = "センター";
centerBone.Flag |= BoneFlags.MOVE;
pmx.BoneArray[0].BoneName = "全ての親";
pmx.BoneArray[0].Flag |= BoneFlags.MOVE;
}
var spine = pmx.BoneArray.Where(b => b.BoneName.Equals("上半身")).FirstOrDefault();
if (0 <= centerId && spine != null)
{
spine.ParentId = centerId;
}
var bonesList = new List<PmxBoneData>(pmx.BoneArray);
System.Func<string, string, int, int> addIk = (ikname, targetname, parentid) =>
{
int result = -1;
var ik = ikTemplate.BoneArray.Where(b => b.BoneName.Equals(ikname)).FirstOrDefault();
if (ik != null)
{
ik = (PmxBoneData)ik.Clone();
result = ik.BoneId = bonesList.Count();
ik.ParentId = parentid;
var target = bonesList.Where(b => b.BoneName.Equals(targetname)).FirstOrDefault();
if (target != null)
{
ik.IkTargetId = target.BoneId;
ik.Pos = target.Pos;
}
for (int i = 0; i < ik.IkChilds.Length; i++) {
var name = ikTemplate.BoneArray[ik.IkChilds[i].ChildId].BoneName;
Debug.Log("ik child name : " + name);
var childbone = bonesList.Where(b => b.BoneName.Equals(name)).FirstOrDefault();
Debug.Log("ik child name : " + name);
if (childbone != null)
{
ik.IkChilds[i].ChildId = childbone.BoneId;
}
}
bonesList.Add(ik);
}
return result;
};
{
int pid = addIk("左足IK", "左足首", 0);
if (0 < pid)
addIk("左つま先IK", "左つま先", pid);
}
{
int pid = addIk("右足IK", "右足首", 0);
if (0 < pid)
addIk("右つま先IK", "右つま先", pid);
}
//*
{
var head = bonesList.Where(b => b.BoneName.Equals("頭")).FirstOrDefault();
var eyes = new PmxBoneData()
{
BoneName = "両目",
BoneNameE = "eyes",
BoneId = bonesList.Count(),
Pos = new Vector3(0, head.Pos.y * 1.5f, 0),
ParentId = head.BoneId,
Flag = BoneFlags.VISIBLE | BoneFlags.ROTATE | BoneFlags.OP,
PosOffset = new Vector3(0, 0, -1.0f),
};
bonesList.Add(eyes);
var eyeBones = bonesList.Where(b => b.BoneName.Equals("左目") || b.BoneName.Equals("右目"));
foreach (PmxBoneData bone in eyeBones)
{
bone.LinkParentId = eyes.BoneId;
bone.LinkWeight = 1.0f;
bone.Flag |= BoneFlags.ROTATE_LINK;
}
//transform level set
{
var legsStack = new Stack<PmxBoneData>(bonesList.FindAll(b => b.BoneName.Equals("右足") || b.BoneName.Equals("左足")));
while(0 < legsStack.Count())
{
var bone = legsStack.Pop();
if (!humanoid2mmd.ContainsValue(bone.BoneName))
{
bone.Depth = 2;
}
var childs = bonesList.FindAll(b => b.ParentId == bone.BoneId);
foreach (var child in childs)
legsStack.Push(child);
}
}
}
pmx.BoneArray = bonesList.ToArray();
/**/
}
}
#endregion
{//vertex face blendshape
var vertices = new List<Vector3>();
var normals = new List<Vector3>();
var uvs = new List<Vector2>();
var renderers = new List<Renderer>();
var boneWeights = new List<BoneWeight>();
var faces = new List<int[]>();
var mattex = new List<KeyValuePair<string, string>>();
var materials = new List<Material>();
var morphs = new List<PmxMorphData>();
var orgRenderers = GetComponentsInChildren<Renderer>();
//GetComponentsInChildren<MeshFilter>(true);
var Offsets = new int[orgRenderers.Length];
System.Func<IList, string> getCountLog = (x) => x.ToString() + "count = " + x.Count;
Debug.Log("mesh count:" + orgRenderers.Length);
int vertexCount = 0;
for (int i = 0; i < orgRenderers.Length; i++)
{
//Debug.Log("LoopCount : " + i);
Debug.Log("MeshNames : " + orgRenderers[i].gameObject.name);
var morphMapping = new SortedDictionary<string, string>();
{
morphMapping.Add("Face.M_F00_000_Fcl_ALL_Angry", "怒");
morphMapping.Add("Face.M_F00_000_Fcl_ALL_Fun", "楽");
morphMapping.Add("Face.M_F00_000_Fcl_ALL_Joy", "喜");
morphMapping.Add("Face.M_F00_000_Fcl_ALL_Sorrow", "哀");
morphMapping.Add("Face.M_F00_000_Fcl_ALL_Surprised", "驚");
morphMapping.Add("Face.M_F00_000_Fcl_BRW_Angry", "怒り");
morphMapping.Add("Face.M_F00_000_Fcl_BRW_Fun", "にこり2");
morphMapping.Add("Face.M_F00_000_Fcl_BRW_Joy", "にこり");
morphMapping.Add("Face.M_F00_000_Fcl_BRW_Sorrow", "困る");
morphMapping.Add("Face.M_F00_000_Fcl_BRW_Surprised", "上");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Natural", "目通常");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Angry", "キリッ");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Close", "まばたき");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Close_R", "ウィンク2");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Close_L", "ウィンク2右");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Joy", "笑い");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Joy_R", "ウィンク");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Joy_L", "ウィンク右");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Sorrow", "じと目");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Surprised", "びっくり");
morphMapping.Add("Face.M_F00_000_Fcl_EYE_Extra", "目消");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Close", "口閉");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Up", "口上");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Down", "口下");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Angry", "∧");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Small", "口小");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Large", "口大");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Neutral", "口角上げ");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Fun", "にやり");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Joy", "ワ");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Sorrow", "▲");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_Surprised", "えー");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_A", "あ");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_I", "い");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_U", "う");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_E", "え");
morphMapping.Add("Face.M_F00_000_Fcl_MTH_O", "お");
morphMapping.Add("Face.M_F00_000_Fcl_HA_Fung1", "牙");
morphMapping.Add("Face.M_F00_000_Fcl_HA_Fung1_Low", "牙下");
morphMapping.Add("Face.M_F00_000_Fcl_HA_Fung1_Up", "牙上");
morphMapping.Add("Face.M_F00_000_Fcl_HA_Fung2", "ギザ歯");
morphMapping.Add("Face.M_F00_000_Fcl_HA_Fung2_Low", "ギザ歯下");
morphMapping.Add("Face.M_F00_000_Fcl_HA_Fung2_Up", "ギザ歯上");
morphMapping.Add("EyeExtra.M_F00_000_EyeExtra_On", "はぅ");
}
System.Func<string, string> remapMorphName = (orgName) =>
{
string remapName = orgName;
if (morphMapping.ContainsKey(orgName))
{
remapName = morphMapping[orgName];
}
return remapName;
};
if (!ReplaceMorphName)
{
remapMorphName = (orgName) => orgName;
}
Mesh mesh = null;
var renderer = orgRenderers[i];
bool isSkinned;
if (renderer is SkinnedMeshRenderer)
{
isSkinned = true;
Mesh srcMesh = ((SkinnedMeshRenderer)renderer).sharedMesh;
mesh = srcMesh.Copy(true);
((SkinnedMeshRenderer)renderer).BakeMesh(mesh);
mesh.boneWeights = srcMesh.boneWeights; // restore weights. clear when BakeMesh
// recalc bindposes
mesh.bindposes = srcMesh.bindposes.ToArray();
//mesh.bindposes = bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray();
//var m = src.localToWorldMatrix; // include scaling
var m = default(Matrix4x4);
m.SetTRS(Vector3.zero, transform.rotation, Vector3.one); // rotation only
mesh.ApplyMatrix(m);
//mesh = ((SkinnedMeshRenderer)renderer).sharedMesh;
}
else if (renderer is MeshRenderer)
{
isSkinned = false;
var mfilter = renderer.GetComponent<MeshFilter>();
//mesh = mfilter.sharedMesh;
mesh = mfilter.sharedMesh.Copy(false);
mesh.ApplyMatrix(renderer.gameObject.transform.localToWorldMatrix);
//mesh.vertices = mesh.vertices.Select(v => renderer.gameObject.transform.localToWorldMatrix.MultiplyVector(v)).ToArray();
}
else
continue;
//vertex
Offsets[i] = vertexCount;
vertexCount += mesh.vertexCount;
vertices.AddRange(mesh.vertices);
normals.AddRange(mesh.normals);
uvs.AddRange(mesh.uv.Select(x => new Vector2() { x = x.x, y = -x.y }));
renderers.AddRange(mesh.vertices.Select(v => renderer));
var count = mesh.boneWeights != null ? mesh.boneWeights.Length : 0;
boneWeights.AddRange(count != 0
? mesh.boneWeights
: mesh.vertices.Select(v => new BoneWeight() { boneIndex0 = -1, weight0 = 1 })
);
//Debug.Log("mesh concat : " + getCountLog(boneWeights));
//face
if (isSkinned)
for (int subIdx = 0; subIdx < renderer.sharedMaterials.Length; subIdx++)
faces.Add(mesh.GetTriangles(subIdx, true).Select(tri => Offsets[i] + tri).ToArray());
else
faces.Add(mesh.triangles.Select(x => x + Offsets[i]).ToArray());
materials.AddRange(renderer.sharedMaterials);
Debug.Log(renderer.sharedMaterials);
//materials
Debug.Log("MaterialCount : " + renderer.sharedMaterials.Length);
//Debug.Log("MaterialCount : " + renderer.sharedMaterials.Length);
mattex.AddRange(renderer.sharedMaterials.Select(x =>
{
/*
Debug.Log("Textures");
x.GetTexturePropertyNames().Select(t => { Debug.Log(t); return t; }).ToArray();
*/
Debug.Log(x.GetTexture("_MainTex").name);
return new KeyValuePair<string, string>(
x.name
, x.GetTexture("_MainTex") != null ? x.GetTexture("_MainTex").name : ""
);
}));
//morph
var blendShapes = Enumerable.Range(0, mesh.blendShapeCount).Select(idx =>
{
var name = mesh.GetBlendShapeName(idx);
var bpos = new Vector3[mesh.vertexCount];
var bnol = new Vector3[mesh.vertexCount];
var btan = new Vector3[mesh.vertexCount];
var maxframe = mesh.GetBlendShapeFrameCount(idx);
mesh.GetBlendShapeFrameVertices(idx, maxframe - 1, bpos, bnol, btan);
var m = transform.localToWorldMatrix;
m.SetColumn(3, new Vector4(0, 0, 0, 1)); // remove translation
var srBpos = bpos.Select(x => m.MultiplyPoint(x)).ToArray();
var blendPos = srBpos.Select((pos, deltaIdx) => new { vertexIndex = Offsets[i] + deltaIdx, delta = pos}).ToArray();
return new { blendIdx = idx, name = name, blendPos = blendPos };
});
morphs.AddRange(
blendShapes.Select(x => new PmxMorphData()
{
MorphName = remapMorphName(x.name),
MorphNameE = x.name,
MorphType = MorphType.VERTEX,
MorphArray = (x.blendPos.Select(pos => (IPmxMorphTypeData)new PmxMorphVertexData()
{
Index = pos.vertexIndex,
Position = pos.delta
}).ToArray())
}).ToArray());
}
#region build
Debug.Log(getCountLog(vertices));
Debug.Log(getCountLog(normals));
Debug.Log(getCountLog(uvs));
Debug.Log(getCountLog(renderers));
Debug.Log(getCountLog(boneWeights));
Debug.Log(getCountLog(mattex));
#region build_vertex
var buildVertices = new List<PmxVertexData>();
foreach (var pos in vertices.Select((vertex, index) => new { vertex, index }))
{
var boneWeightOrg = new[]{
new {id = boneWeights[pos.index].boneIndex0 , weight = boneWeights[pos.index].weight0},
new {id = boneWeights[pos.index].boneIndex1 , weight = boneWeights[pos.index].weight1},
new {id = boneWeights[pos.index].boneIndex2 , weight = boneWeights[pos.index].weight2},
new {id = boneWeights[pos.index].boneIndex3 , weight = boneWeights[pos.index].weight3},
};
int[] boneidRemaped;
float[] weightRemaped;
if (renderers[pos.index] is SkinnedMeshRenderer)
{
var smr = (SkinnedMeshRenderer)renderers[pos.index];
var boneWeightOrgFilterd = boneWeightOrg.Where(x => 0 < x.weight);
var boneWeightRemaped = boneWeightOrgFilterd.Select(x =>
{
var remapedBone = pmx.BoneArray.Select((b, i) => new { id = i, bone = b }).Where(b => smr.bones[x.id].name.Equals(b.bone.BoneNameE)).FirstOrDefault();
return new { id = remapedBone == null ? 0 : remapedBone.id, weight = x.weight };
});
boneidRemaped = boneWeightRemaped.Select(x => x.id).Concat(Enumerable.Range(0, 4).Select(y => 0)).Take(4).ToArray();
weightRemaped = boneWeightRemaped.Select(x => x.weight).Concat(Enumerable.Range(0, 4).Select(y => 0.0f)).Take(4).ToArray();
}
else
{
//var parentBone = pmx.BoneArray.Select((b, i) => new { id = i, bone = b }).Where(pb => pb.bone.BoneNameE.Equals(renderers[pos.index].transform.parent.name)).FirstOrDefault();
var parentBone = pmx.BoneArray.Select((b, i) => new { id = i, bone = b }).Where(pb => pb.bone.BoneNameE.Equals(renderers[pos.index].transform.name)).FirstOrDefault();
boneidRemaped = new int[] { parentBone == null ? 0 : parentBone.id, 0, 0, 0 };
weightRemaped = new float[] { 1, 0, 0, 0 };
}
if (boneidRemaped.Length != 4)
Debug.LogError("boneidRemaped count " + boneidRemaped.Length);
if (weightRemaped.Length != 4)
Debug.LogError("weightRemaped count " + weightRemaped.Length);
buildVertices.Add(new PmxVertexData()
{
Pos = pos.vertex,
Normal = normals[pos.index],
Uv = uvs[pos.index],
WeightType = WeightType.BDEF4,
BoneId = boneidRemaped,
Weight = weightRemaped,
Edge = 1.0f,
});
}
pmx.VertexArray = buildVertices.ToArray();
Debug.Log("VertexCount = " + pmx.VertexArray.Length);
#endregion
#region build_face
pmx.VertexIndices = faces.SelectMany(x => x).ToArray();
Debug.Log("FaceCount = " + pmx.VertexIndices.Length);
#endregion
#region build_material_wip
//long faceBorder = 0;
pmx.TextureFiles = mattex.Select(x => x.Value).Distinct().ToArray();
Debug.Log("TextureFiles Count = " + pmx.TextureFiles.Length);
var orgMaterialTable = from face in faces.Select((f, i) => new { face = f, index = i })
join tex in mattex.Select((t, i) => new { texture = t, index = i })
on face.index equals tex.index
join mat in materials.Select((m, i) => new { material = m, index = i })
on face.index equals mat.index
select new { face.face, tex.texture, mat.material };
var buildMaterial = orgMaterialTable.Select(x =>
{
var diffuse = new Vector4() { x = 1, y = 1, z = 1, w = 1 };
var ambient = new Vector4() { x = 0.5f, y = 0.5f, z = 0.5f, w = 1 };
var spec = new Vector4() { x = 0.5f, y = 0.5f, z = 0.5f, w = 1 };
try
{
var color = x.material.GetColor("_Color");
diffuse.x = color.r;
diffuse.y = color.g;
diffuse.z = color.b;
diffuse.w = color.a;
}
catch (System.Exception e) { }
try
{
var emissionColor = x.material.GetColor("_EmissionColor");
spec.x = emissionColor.r;
spec.y = emissionColor.g;
spec.z = emissionColor.b;
//ambient.w = emissionColor.a;
}
catch (System.Exception e) { }
try
{
var shadowColor = x.material.GetColor("_ShadeColor");
ambient.x = shadowColor.r;
ambient.y = shadowColor.g;
ambient.z = shadowColor.b;
//spec.w = shadowColor.a;
}
catch (System.Exception e) { }
return new PmxMaterialData()
{
FaceCount = x.face.Length,
TextureId = ArrayUtility.IndexOf(pmx.TextureFiles, x.texture.Value),
ToonId = -1,
SphereId = -1,
MaterialName = x.texture.Key,
MaterialNameE = x.texture.Key,
Diffuse = diffuse,
Ambient = ambient,
Specular = spec,
Shininess = 1.0f,
Flag = RenderFlags.EDGE | RenderFlags.GROUND_SHADOW | RenderFlags.SLEF_SHADOW | RenderFlags.TO_SHADOW_MAP,
};
});
pmx.MaterialArray = buildMaterial.ToArray();
Debug.Log("Material Count = " + pmx.MaterialArray.Length);
pmx.TextureFiles = pmx.TextureFiles.Select(x => "tex\\" + x + ".png").ToArray();
#endregion
#region build_morph
var rebuildMorph = morphs.Select(x =>
new PmxMorphData
{
MorphName = x.MorphName,
MorphNameE = x.MorphNameE,
MorphType = x.MorphType,
MorphArray = x.MorphArray.Where(delta => pmx.VertexArray[((PmxMorphVertexData)delta).Index].Pos != ((PmxMorphVertexData)delta).Position).ToArray()
});
pmx.MorphArray = rebuildMorph.ToArray();
#endregion
#endregion
}
slots.Add(new PmxSlotData()
{
Indices = pmx.BoneArray.Select((x, i) => i).ToArray(),
NormalSlot = false,
Type = SlotType.BONE,
SlotName = "Root",
SlotNameE = "Root"
});
slots.Add(new PmxSlotData()
{
Indices = pmx.MorphArray.Select((x, i) => i).ToArray(),
NormalSlot = false,
Type = SlotType.MORPH,
SlotName = "表情",
SlotNameE = "Exp"
});
pmx.SlotArray = slots.ToArray();
System.Func<int, byte> getIndexSize = (count) =>
{
if(count < sbyte.MaxValue)
{
return 1;
}else if(count < short.MaxValue)
{
return 2;
}
else
{
return 4;
}
};
{
//pmx.Header.Version = 2.0f;
pmx.Header.NumberOfExtraUv = 0;
pmx.Header.VertexIndexSize = getIndexSize(pmx.VertexArray.Length);
pmx.Header.TextureIndexSize = getIndexSize(pmx.TextureFiles.Length);
pmx.Header.MaterialIndexSize = getIndexSize(pmx.MaterialArray.Length);
pmx.Header.BoneIndexSize = getIndexSize(pmx.BoneArray.Length);
pmx.Header.MorphIndexSize = getIndexSize(pmx.MorphArray.Length);
pmx.Header.RigidIndexSize = 1;
pmx.Header.ModelName = name;
pmx.Header.ModelNameE = name;
pmx.Header.Description = "Unity PMXExporter exported.";
pmx.Header.DescriptionE = "Unity PMXExporter exported.";
};
var filename = savepath;
using (FileStream fs = new FileStream(filename, FileMode.OpenOrCreate))
using (BinaryWriter bw = new BinaryWriter(fs))
{
pmx.Write(bw);
}
Debug.Log(filename + " is exported.");
}
finally
{
if (ConvertArmatuar)
{
if (tmpRootRot != null) {
transform.localScale /= caScaling;
transform.rotation = (Quaternion)tmpRootRot;
}
var anim = GetComponent<Animator>();
var lua = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm);
if(tmpLUARot != null)
lua.rotation = (Quaternion)tmpLUARot;
var rua = anim.GetBoneTransform(HumanBodyBones.RightUpperArm);
if (tmpRUARot != null)
rua.rotation = (Quaternion)tmpRUARot;
}
}
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment