private object BorrarItem() { var item = PMD.ItemSeleccionado as DTOBase; PMD.BorrarItem(); return(true); }
Vector3[] EntryNormals(PMD.PMDFormat format) { int vcount = (int)format.vertex_list.vert_count; Vector3[] normals = new Vector3[vcount]; for (int i = 0; i < vcount; i++) normals[i] = format.vertex_list.vertex[i].normal_vec; return normals; }
Vector2[] EntryUVs(PMD.PMDFormat format) { int vcount = (int)format.vertex_list.vert_count; Vector2[] uvs = new Vector2[vcount]; for (int i = 0; i < vcount; i++) uvs[i] = format.vertex_list.vertex[i].uv; return uvs; }
// 頂点座標やUVなどの登録だけ void EntryAttributesForMesh(PMD.PMDFormat format, Mesh mesh) { //mesh.vertexCount = (int)format.vertex_list.vert_count; mesh.vertices = EntryVertices(format); mesh.normals = EntryNormals(format); mesh.uv = EntryUVs(format); mesh.boneWeights = EntryBoneWeights(format); }
Vector3[] EntryVertices(PMD.PMDFormat format) { int vcount = (int)format.vertex_list.vert_count; Vector3[] vpos = new Vector3[vcount]; for (int i = 0; i < vcount; i++) vpos[i] = format.vertex_list.vertex[i].pos; return vpos; }
BoneWeight[] EntryBoneWeights(PMD.PMDFormat format) { int vcount = (int)format.vertex_list.vert_count; BoneWeight[] weights = new BoneWeight[vcount]; for (int i = 0; i < vcount; i++) { weights[i].boneIndex0 = (int)format.vertex_list.vertex[i].bone_num[0]; weights[i].boneIndex1 = (int)format.vertex_list.vertex[i].bone_num[1]; weights[i].weight0 = format.vertex_list.vertex[i].bone_weight; weights[i].weight1 = 100 - format.vertex_list.vertex[i].bone_weight; } return weights; }
/// <summary> /// プレファブを作成する /// </summary> /// <param name='shader_type'>シェーダーの種類</param> /// <param name='use_rigidbody'>剛体を使用するか</param> /// <param name='use_mecanim'>Mecanimを使用するか</param> /// <param name='use_ik'>IKを使用するか</param> /// <param name='scale'>スケール</param> /// <param name='is_pmx_base_import'>PMX Baseでインポートするか</param> public void CreatePrefab(PMD.PMDConverter.ShaderType shader_type, bool use_rigidbody, bool use_mecanim, bool use_ik, float scale, bool is_pmx_base_import) { GameObject game_object; Object prefab; if (is_pmx_base_import) { //PMX Baseでインポートする //PMXファイルのインポート PMX.PMXFormat format = PMXLoaderScript.Import(file_path_); //ゲームオブジェクトの作成 game_object = PMXConverter.CreateGameObject(format, use_rigidbody, use_mecanim, use_ik, scale); // プレファブに登録 prefab = PrefabUtility.CreateEmptyPrefab(format.meta_header.folder + "/" + format.meta_header.name + ".prefab"); } else { //V2エクスポーターを使用しない //PMDファイルのインポート if (null == format_) { //まだ読み込んでいないなら読むこむ try { //PMX読み込みを試みる format_ = PMXLoaderScript.PmdImport(file_path_); } catch (System.FormatException) { //PMXとして読み込めなかったら //PMDとして読み込む format_ = PMDLoaderScript.Import(file_path_); } header_ = format_.head; } //ゲームオブジェクトの作成 game_object = PMDConverter.CreateGameObject(format_, shader_type, use_rigidbody, use_mecanim, use_ik, scale); // プレファブに登録 prefab = PrefabUtility.CreateEmptyPrefab(format_.folder + "/" + format_.name + ".prefab"); } PrefabUtility.ReplacePrefab(game_object, prefab); // アセットリストの更新 AssetDatabase.Refresh(); // 一度,表示されているモデルを削除して新しくPrefabのインスタンスを作る GameObject.DestroyImmediate(game_object); PrefabUtility.InstantiatePrefab(prefab); }
void SetSubMesh(PMD.PMDFormat format, Mesh mesh) { // マテリアル対サブメッシュ // サブメッシュとはマテリアルに適用したい面頂点データのこと // 面ごとに設定するマテリアルはここ mesh.subMeshCount = (int)format.material_list.material_count; int sum = 0; for (int i = 0; i < mesh.subMeshCount; i++) { int count = (int)format.material_list.material[i].face_vert_count; int[] indices = new int[count*3]; // 面頂点は材質0から順番に加算されている for (int j = 0; j < count; j++) indices[j] = format.face_vertex_list.face_vert_index[j+sum]; mesh.SetTriangles(indices, i); sum += (int)format.material_list.material[i].face_vert_count; } }
//エッジマテリアル確認(true:エッジ有り, false:無エッジ) bool IsEdgeMaterial(PMD.PMDFormat.Material model_material) { bool result; if (0 == model_material.edge_flag) { //エッジ無し result = false; } else { //エッジ有りなら result = true; } return result; }
//背面カリングマテリアル確認(true:背面カリングする, false:背面カリングしない) bool IsCullBackMaterial(PMD.PMDFormat.Material model_material) { bool result; if (1.0f <= model_material.alpha) { //不透明なら //背面カリングする result = true; } else if (0.99f <= model_material.alpha) { //不透明の両面描画なら //背面カリングしない result = false; } else { //透過なら //背面カリングしない result = false; } return result; }
//IKSolverScript[] CreateIKBoneList(PMD.PMDFormat.IKList ik_list, GameObject[] bones) //{ // IKSolverScript[] solvers = new IKSolverScript[ik_list.ik_data_count]; // // IKの数だけ回す // for (int i = 0; i < ik_list.ik_data_count; i++) // { // // IKについた子の数だけ回す // PMD.PMDFormat.IK ik = ik_list.ik_data[i]; // // 子ボーンの取得 // GameObject[] childs = new GameObject[ik.ik_chain_length]; // for (int j = 0; j < ik.ik_chain_length; j++) // childs[j] = bones[ik.ik_child_bone_index[j]]; // // コンポーネントを追加しつつ、根本ボーンの登録 // solvers[i] = bones[ik_list.ik_data[i].ik_bone_index].AddComponent<IKSolverScript>(); // IKSolverScript.SetAttribute(solvers[i], bones[ik.ik_target_bone_index], childs, ik.iterations, ik.control_weight); // } // return solvers; //} // IKの登録 // IKは基本的にスクリプトを利用 public void EntryIKSolver(PMD.PMDFormat format, GameObject[] bones) { //PMD.PMDFormat.IKList ik_list = format.ik_list; // 悪さする可能性があるのでIKはOFF //IKSolverScript[] solvers = CreateIKBoneList(ik_list, bones); }
//無影マテリアル確認(true:無影, false:影放ち) bool IsNoCastShadowMaterial(PMD.PMDFormat.Material model_material) { bool result; if (0 == model_material.edge_flag) { //エッジ無し //無影 result = true; } else { //エッジ有りなら //影放ち result = false; } return result; }
// バインドポーズの作成 public void BuildingBindpose(PMD.PMDFormat format, Mesh mesh, Material[] materials, GameObject[] bones) { // 行列とかトランスフォームとか Matrix4x4[] bindpose = new Matrix4x4[bones.Length]; Transform[] trans = new Transform[bones.Length]; for (int i = 0; i < bones.Length; i++) { trans[i] = bones[i].transform; bindpose[i] = bones[i].transform.worldToLocalMatrix; } // ここで本格的な適用 SkinnedMeshRenderer smr = format.caller.AddComponent<SkinnedMeshRenderer>() as SkinnedMeshRenderer; mesh.bindposes = bindpose; smr.sharedMesh = mesh; smr.bones = trans; smr.materials = materials; }
string GetMMDShaderPath(PMD.PMDFormat.Material model_material, Texture2D texture) { string result = "MMD/"; if (IsTransparentMaterial(model_material, texture)) { result += "Transparent/"; } result += "PMDMaterial"; if (IsEdgeMaterial(model_material)) { result += "-with-Outline"; } if (IsCullBackMaterial(model_material)) { result += "-CullBack"; } if (IsNoCastShadowMaterial(model_material)) { result += "-NoCastShadow"; } #if MFU_ENABLE_NO_RECEIVE_SHADOW_SHADER //影受け無しのシェーダはまだ無いので無効化 if (IsNoReceiveShadowMaterial(model_material)) { result += "-NoReceiveShadow"; } #endif //MFU_ENABLE_NO_RECEIVE_SHADOW_SHADER return result; }
public Mesh CreateMesh(PMD.PMDFormat format) { Mesh mesh = new Mesh(); EntryAttributesForMesh(format, mesh); SetSubMesh(format, mesh); CreateAssetForMesh(format, mesh); return mesh; }
//影受け無しマテリアル確認(true:影受け無し, false:影受け) bool IsNoReceiveShadowMaterial(PMD.PMDFormat.Material model_material) { bool result; if (0.98f == model_material.alpha) { //浮動小数点の比較だけど、0.98fとの同値確認でPMXエディタの0.98と一致したので一旦これで。 //影受け無し(不透明度が0.98fは特別扱いで影受け無し)なら result = true; } else { //影受け有りなら result = false; } return result; }
//透過マテリアル確認(true:透過, false:不透明) bool IsTransparentMaterial(PMD.PMDFormat.Material model_material, Texture2D texture) { bool result = false; result = result || (model_material.alpha < 0.98f); //0.98f以上は不透明と見做す(0.98fに影生成情報を埋め込んでいる為) if (null != texture) { result = result || texture.alphaIsTransparency; } return result; }
public BaseClassDescriptor(TypeDescriptor typeDescriptor, uint numContainedBases, PMD displacementData) { TypeDescriptor = typeDescriptor ?? throw new ArgumentNullException(nameof(typeDescriptor)); NumContainedBases = numContainedBases; DisplacementData = displacementData; }
// 親子関係の構築 void AttachParentsForBone(PMD.PMDFormat format, GameObject[] bones) { for (int i = 0; i < bones.Length; i++) { int index = format.bone_list.bone[i].parent_bone_index; if (index != 0xFFFF) bones[i].transform.parent = bones[index].transform; else bones[i].transform.parent = format.caller.transform; } }
// マテリアルの生成 public Material[] CreateMaterials(PMD.PMDFormat format) { Material[] materials; materials = EntryAttributesForMaterials(format); CreateAssetForMaterials(format, materials); return materials; }
// マテリアルの登録 void CreateAssetForMaterials(PMD.PMDFormat format, Material[] mats) { // 適当なフォルダに投げる string path = format.folder + "/Materials/"; AssetDatabase.CreateFolder(format.folder, "Materials"); for (int i = 0; i < mats.Length; i++) { string fname = path + format.name + "_material" + i + ".asset"; AssetDatabase.CreateAsset(mats[i], fname); } }
// マテリアルに必要な色などを登録 Material[] EntryAttributesForMaterials(PMD.PMDFormat format) { int count = (int)format.material_list.material_count; Material[] mats = new Material[count]; EntryColors(format, mats, format.shader_type); return mats; }
// 表情ボーンの生成を行う void CreateSkinBone(PMD.PMDFormat format, GameObject[] bones) { // 表情ルートを生成してルートの子供に付ける GameObject skin_root = new GameObject("Expression"); if (skin_root.GetComponent<ExpressionManagerScript>() == null) skin_root.AddComponent<ExpressionManagerScript>(); skin_root.transform.parent = format.caller.transform; for (int i = 0; i < format.skin_list.skin_count; i++) { // 表情を親ボーンに付ける GameObject skin = new GameObject(format.skin_list.skin_data[i].skin_name); skin.transform.parent = skin_root.transform; var script = skin.AddComponent<MMDSkinsScript>(); // モーフの情報を入れる AssignMorphVectorsForSkin(format.skin_list.skin_data[i], format.vertex_list, script); } }
// メッシュをProjectに登録 void CreateAssetForMesh(PMD.PMDFormat format, Mesh mesh) { AssetDatabase.CreateAsset(mesh, format.folder + "/" + format.name + ".asset"); }
// モーフ情報(頂点インデックス、モーフ先頂点など)を記録する void AssignMorphVectorsForSkin(PMD.PMDFormat.SkinData data, PMD.PMDFormat.VertexList vtxs, MMDSkinsScript script) { uint count = data.skin_vert_count; int[] indices = new int[count]; Vector3[] morph_target = new Vector3[count]; for (int i = 0; i < count; i++) { // ここで設定する indices[i] = (int)data.skin_vert_data[i].skin_vert_index; // モーフ先 - 元頂点 //morph_target[i] = (data.skin_vert_data[i].skin_vert_pos - vtxs.vertex[indices[i]].pos).normalized; //morph_target[i] = data.skin_vert_data[i].skin_vert_pos - vtxs.vertex[indices[i]].pos; morph_target[i] = data.skin_vert_data[i].skin_vert_pos; } // スクリプトに記憶させる script.morphTarget = morph_target; script.targetIndices = indices; switch (data.skin_type) { case 0: script.skinType = MMDSkinsScript.SkinType.Base; script.gameObject.name = "base"; break; case 1: script.skinType = MMDSkinsScript.SkinType.EyeBrow; break; case 2: script.skinType = MMDSkinsScript.SkinType.Eye; break; case 3: script.skinType = MMDSkinsScript.SkinType.Lip; break; case 4: script.skinType = MMDSkinsScript.SkinType.Other; break; } }
// ボーンの位置決めや親子関係の整備など GameObject[] EntryAttributeForBones(PMD.PMDFormat format) { int count = format.bone_list.bone_count; GameObject[] bones = new GameObject[count]; for (int i = 0; i < count; i++) { bones[i] = new GameObject(format.bone_list.bone[i].bone_name); bones[i].transform.name = bones[i].name; bones[i].transform.position = format.bone_list.bone[i].bone_head_pos; } return bones; }
// 色の生成 void EntryColors(PMD.PMDFormat format, Material[] mats, ShaderType shader_type) { // マテリアルの生成 for (int i = 0; i < mats.Length; i++) { // PMDフォーマットのマテリアルを取得 PMD.PMDFormat.Material pmdMat = format.material_list.material[i]; switch (shader_type) { case ShaderType.Default: // デフォルト mats[i] = new Material(Shader.Find("Transparent/Diffuse")); mats[i].color = pmdMat.diffuse_color; Color cbuf = mats[i].color; cbuf.a = pmdMat.alpha; // これでいいのか? mats[i].color = cbuf; break; case ShaderType.HalfLambert: // ハーフランバート mats[i] = new Material(Shader.Find("Custom/CharModel")); mats[i].SetFloat("_Cutoff", 1 - pmdMat.alpha); mats[i].color = pmdMat.diffuse_color; break; case ShaderType.MMDShader: if (pmdMat.edge_flag == 1) { // エッジがあるよ mats[i] = new Material(Shader.Find("MMD/Transparent/PMDMaterial-with-Outline")); mats[i].SetFloat("_OutlineWidth", 0.2f); // これぐらいがいい気がする } else { mats[i] = new Material(Shader.Find("MMD/Transparent/PMDMaterial")); } mats[i].SetColor("_Color", pmdMat.diffuse_color); mats[i].SetColor("_AmbColor", pmdMat.mirror_color); mats[i].SetFloat("_Opacity", pmdMat.alpha); mats[i].SetColor("_SpecularColor", pmdMat.specular_color); mats[i].SetFloat("_Shininess", pmdMat.specularity); // ここでスフィアマップ string path = format.folder + "/" + pmdMat.sphere_map_name; Texture sphere_map; if (File.Exists(path)) { // ファイルの存在を確認 sphere_map = UnityEditor.AssetDatabase.LoadAssetAtPath(path, typeof(Texture)) as Texture; // 乗算と加算判定 string ext = Path.GetExtension(pmdMat.sphere_map_name); if (ext == ".spa") { // 加算 mats[i].SetTexture("_SphereAddTex", sphere_map); mats[i].SetTextureScale("_SphereAddTex", new Vector2(1, -1)); } else if (ext == ".sph") { // 乗算 mats[i].SetTexture("_SphereMulTex", sphere_map); mats[i].SetTextureScale("_SphereMulTex", new Vector2(1, -1)); } } // トゥーンの位置を取得 string toon_name = pmdMat.toon_index != 0xFF ? format.toon_texture_list.toon_texture_file[pmdMat.toon_index] : "toon00.bmp"; string resource_path = UnityEditor.AssetDatabase.GetAssetPath(Shader.Find("MMD/HalfLambertOutline")); resource_path = Path.GetDirectoryName(resource_path); // resourceディレクトリを取得 resource_path += "/toon/" + toon_name; // トゥーンが存在するか確認 if (!File.Exists(resource_path)) { // 自前トゥーンの可能性がある resource_path = format.folder + "/" + format.toon_texture_list.toon_texture_file[pmdMat.toon_index]; if (!File.Exists(resource_path)) { Debug.LogError("Do not exists toon texture: " + format.toon_texture_list.toon_texture_file[pmdMat.toon_index]); break; } } // テクスチャの割り当て Texture toon_tex = UnityEditor.AssetDatabase.LoadAssetAtPath(resource_path, typeof(Texture)) as Texture; mats[i].SetTexture("_ToonTex", toon_tex); mats[i].SetTextureScale("_ToonTex", new Vector2(1, -1)); break; } // テクスチャが空でなければ登録 if (pmdMat.texture_file_name != "") { string path = format.folder + "/" + pmdMat.texture_file_name; mats[i].mainTexture = AssetDatabase.LoadAssetAtPath(path, typeof(Texture)) as Texture; mats[i].mainTextureScale = new Vector2(1, -1); } } }
// ボーンの生成 public GameObject[] CreateBones(PMD.PMDFormat format) { GameObject[] bones; bones = EntryAttributeForBones(format); AttachParentsForBone(format, bones); CreateSkinBone(format, bones); return bones; }
// IKの登録 // IKは基本的にスクリプトを利用 public CCDIKSolver[] EntryIKSolver(PMD.PMDFormat format, GameObject[] bones) { PMD.PMDFormat.IKList ik_list = format.ik_list; CCDIKSolver[] iksolvers = new CCDIKSolver[ik_list.ik_data_count]; for (int i = 0; i < ik_list.ik_data_count; i++) { PMD.PMDFormat.IK ik = ik_list.ik_data[i]; bones[ik.ik_bone_index].AddComponent<CCDIKSolver>(); CCDIKSolver solver = bones[ik.ik_bone_index].GetComponent<CCDIKSolver>(); solver.target = bones[ik.ik_target_bone_index].transform; solver.controll_weight = ik.control_weight * 4; // PMDファイルは4倍らしい solver.iterations = ik.iterations; solver.chains = new Transform[ik.ik_chain_length]; for (int j = 0; j < ik.ik_chain_length; j++) solver.chains[j] = bones[ik.ik_child_bone_index[j]].transform; if (!(bones[ik.ik_bone_index].name.Contains("足") || bones[ik.ik_bone_index].name.Contains("つま先"))) { solver.enabled = false; } iksolvers[i] = solver; } return iksolvers; }