public HelixViewerPanel(string path) { InitializeComponent(); var builder = new MeshBuilder(); format_ = LoadPmxMaterials(path); MeshCreationInfo creation_info = CreateMeshCreationInfoSingle(); var mats = format_.material_list.material.Length; var models = new Model3DGroup(); for (int i = 0, i_max = creation_info.value.Length; i < i_max; ++i) { //format_.face_vertex_list.face_vert_indexを[start](含む)から[start+count](含まず)迄取り出し int[] indices = creation_info.value[i].plane_indices.Select(x => (int)creation_info.reassign_dictionary[x]) //頂点リアサインインデックス変換 .ToArray(); MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions = new Point3DCollection(format_.vertex_list.vertex.Select(x => x.pos)); mesh.TextureCoordinates = new PointCollection(format_.vertex_list.vertex.Select(x => x.uv)); indices.ToList() .ForEach(x => mesh.TriangleIndices.Add(x)); var textureIndex = format_.material_list.material[i].usually_texture_index; Material material; if (textureIndex == uint.MaxValue) { material = new DiffuseMaterial(new SolidColorBrush(Color.FromRgb(160, 160, 160))); } else { // Texture ImageBrush colors_brush = new ImageBrush { ImageSource = new BitmapImage( new Uri(Path.Combine(format_.meta_header.folder, format_.texture_list.texture_file[textureIndex]), UriKind.Relative)) }; material = new DiffuseMaterial(colors_brush); } var model = new GeometryModel3D(mesh, material); model.BackMaterial = material; models.Children.Add(model); } PreviewModel.Content = models; }
/// <summary> /// メッシュを作成する為の情報を作成(複数メッシュ版) /// </summary> /// <returns>メッシュ作成情報</returns> private MeshCreationInfo[] CreateMeshCreationInfoMulti() { //マテリアル単位のMeshCreationInfo.Packを作成する var packs = CreateMeshCreationInfoPacks(); //マテリアル細分化 packs = SplitSubMesh(packs); //頂点数の多い順に並べる(メッシュ分割アルゴリズム上、後半に行く程頂点数が少ない方が敷き詰め効率が良い) Array.Sort(packs, (x, y) => y.vertices.Length - x.vertices.Length); var result = new List <MeshCreationInfo>(); do { uint vertex_sum = 0; var info = new MeshCreationInfo(); //マテリアルパック作成 info.value = Enumerable.Range(0, packs.Length) .Where(x => null != packs[x]) //有効なマテリアルに絞る .Where(x => { //採用しても頂点数が限界を超えないなら vertex_sum += (uint)packs[x].vertices.Length; return(vertex_sum < c_max_vertex_count_in_mesh); }) .Select(x => { //マテリアルの採用と無効化 var pack = packs[x]; packs[x] = null; return(pack); }) .ToArray(); //マテリアルインデックスに並べる(メッシュの選定が終わったので見易い様に並びを戻す) Array.Sort(info.value, (x, y) => x.material_index > y.material_index ? 1 : x.material_index < y.material_index ? -1 : 0); //総頂点作成 info.all_vertices = info.value.SelectMany(x => x.vertices).Distinct().ToArray(); Array.Sort(info.all_vertices); //頂点リアサインインデックス用辞書作成 info.reassign_dictionary = new Dictionary <uint, uint>(); uint reassign_index = 0; foreach (var i in info.all_vertices) { info.reassign_dictionary[i] = reassign_index++; } //戻り値に追加 result.Add(info); } while (packs.Any(x => null != x)); //使用していないマテリアルが為るならループ return(result.ToArray()); }
/// <summary> /// メッシュにサブメッシュを登録する /// </summary> /// <param name='mesh'>対象メッシュ</param> /// <param name='creation_info'>メッシュ作成情報</param> private void SetSubMesh(Mesh mesh, MeshCreationInfo creation_info) { // マテリアル対サブメッシュ // サブメッシュとはマテリアルに適用したい面頂点データのこと // 面ごとに設定するマテリアルはここ mesh.subMeshCount = creation_info.value.Length; for (int i = 0, i_max = creation_info.value.Length; i < i_max; ++i) { //format_.face_vertex_list.face_vert_indexを[start](含む)から[start+count](含まず)迄取り出し var indices = creation_info.value[i].plane_indices .Select(x => (int)creation_info.reassign_dictionary[x]) //頂点リアサインインデックス変換 .ToArray(); mesh.SetTriangles(indices, i); } }
MeshCreationInfo CreateMeshCreationInfoSingle() { MeshCreationInfo result = new MeshCreationInfo(); //全マテリアルを設定 result.value = CreateMeshCreationInfoPacks(); //全頂点を設定 result.all_vertices = Enumerable.Range(0, format_.vertex_list.vertex.Length).Select(x => (uint)x).ToArray(); //頂点リアサインインデックス用辞書作成 result.reassign_dictionary = new Dictionary <uint, uint>(result.all_vertices.Length); for (uint i = 0, i_max = (uint)result.all_vertices.Length; i < i_max; ++i) { result.reassign_dictionary[i] = i; } return(result); }
/// <summary> /// メッシュに基本情報(頂点座標・法線・UV・ボーンウェイト)を登録する /// </summary> /// <param name='mesh'>対象メッシュ</param> /// <param name='creation_info'>メッシュ作成情報</param> private void EntryAttributesForMesh(Mesh mesh, MeshCreationInfo creation_info) { mesh.vertices = creation_info.all_vertices.Select(x => format_.vertex_list.vertex[x].pos * scale_) .ToArray(); mesh.normals = creation_info.all_vertices.Select(x => format_.vertex_list.vertex[x].normal_vec).ToArray(); mesh.uv = creation_info.all_vertices.Select(x => format_.vertex_list.vertex[x].uv).ToArray(); if (0 < format_.header.additionalUV) { //追加UVが1つ以上有れば //1つ目のみ登録 mesh.uv2 = creation_info.all_vertices.Select(x => new Vector2(format_.vertex_list.vertex[x].add_uv[0].x, format_.vertex_list.vertex[x].add_uv[0].y)).ToArray(); } mesh.boneWeights = creation_info.all_vertices .Select(x => ConvertBoneWeight(format_.vertex_list.vertex[x].bone_weight)).ToArray(); mesh.colors = creation_info.all_vertices.Select(x => new Color(0.0f, 0.0f, 0.0f, format_.vertex_list.vertex[x].edge_magnification * 0.25f)) .ToArray(); //不透明度にエッジ倍率を0.25倍した情報を仕込む(0~8迄は表せる) }
/// <summary> /// マテリアルをProjectに登録する /// </summary> /// <param name='mesh'>対象マテリアル</param> /// <param name='creation_info'>メッシュ作成情報</param> void CreateAssetForMaterials(Material[] materials, MeshCreationInfo creation_info) { // 適当なフォルダに投げる string path = format_.meta_header.folder + "/Materials/"; if (!System.IO.Directory.Exists(path)) { AssetDatabase.CreateFolder(format_.meta_header.folder, "Materials"); } for (int i = 0, i_max = materials.Length; i < i_max; ++i) { uint material_index = creation_info.value[i].material_index; string name = GetFilePathString(format_.material_list.material[material_index].name); string file_name = path + material_index.ToString() + "_" + name + ".asset"; AssetDatabase.CreateAsset(materials[i], file_name); } }
/// <summary> /// 1マテリアルの頂点数が1メッシュで表現出来ないので分割する /// </summary> /// <returns>メッシュ作成情報のマテリアルパック</returns> /// <param name='creation_infos'>メッシュ作成情報のマテリアルパック</param> List<MeshCreationInfo.Pack> SplitSubMesh(MeshCreationInfo.Pack pack) { List<MeshCreationInfo.Pack> result = new List<MeshCreationInfo.Pack>(); //1メッシュに収まらないなら uint plane_end = (uint)pack.plane_indices.Length; uint plane_start = 0; while (plane_start < plane_end) { //まだ面が有るなら uint plane_count = 0; uint vertex_count = 0; while (true) { //現在の頂点数から考えると、余裕分の1/3迄の数の面は安定して入る //はみ出て欲しいから更に1面(3頂点)を足す plane_count += (c_max_vertex_count_in_mesh - vertex_count) / 3 * 3 + 3; vertex_count = (uint)pack.plane_indices.Skip((int)plane_start) //面頂点インデックス取り出し(先頭) .Take((int)plane_count) //面頂点インデックス取り出し(末尾) .Distinct() //重複削除 .Count(); //個数取得 if (c_max_vertex_count_in_mesh <= vertex_count) { //1メッシュを超えているなら //此処でのメッシュ超えは必ずc_max_vertex_count_in_meshぎりぎりで有り、1面(3頂点)を1つ取れば収まる様になっている plane_count -= 3; break; } if (plane_end <= (plane_start + plane_count)) { //面の最後なら break; } } //分離分を戻り値の追加 MeshCreationInfo.Pack result_pack = new MeshCreationInfo.Pack();; result_pack.material_index = pack.material_index; result_pack.plane_indices = pack.plane_indices.Skip((int)plane_start) //面頂点インデックス取り出し(先頭) .Take((int)plane_count) //面頂点インデックス取り出し(末尾) .ToArray(); result_pack.vertices = result_pack.plane_indices.Distinct() //重複削除 .ToArray(); result.Add(result_pack); //開始点を後ろに plane_start += plane_count; } return result; }
/// <summary> /// モーフ作成 /// </summary> /// <param name='mesh'>対象メッシュ</param> /// <param name='materials'>対象マテリアル</param> /// <param name='bones'>対象ボーン</param> /// <param name='renderers'>対象レンダラー</param> /// <param name='creation_info'>メッシュ作成情報</param> void CreateMorph(Mesh[] mesh, Material[][] materials, GameObject[] bones, SkinnedMeshRenderer[] renderers, MeshCreationInfo[] creation_info) { //表情ルートを生成してルートの子供に付ける GameObject expression_root = new GameObject("Expression"); Transform expression_root_transform = expression_root.transform; expression_root_transform.parent = root_game_object_.transform; //表情マネージャー MorphManager morph_manager = expression_root.AddComponent<MorphManager>(); morph_manager.uv_morph = new MorphManager.UvMorphPack[1 + format_.header.additionalUV]; //UVモーフ数設定 //個別モーフスクリプト作成 GameObject[] morphs = new GameObject[format_.morph_list.morph_data.Length]; for (int i = 0, i_max = format_.morph_list.morph_data.Length; i < i_max; ++i) { morphs[i] = new GameObject(format_.morph_list.morph_data[i].morph_name); // 表情を親ボーンに付ける morphs[i].transform.parent = expression_root_transform; } //グループモーフ作成 CreateGroupMorph(morph_manager, morphs); //ボーンモーフ morph_manager.bones = bones.Select(x=>x.transform).ToArray(); CreateBoneMorph(morph_manager, morphs); //頂点モーフ作成 CreateVertexMorph(morph_manager, morphs, creation_info); //UV・追加UVモーフ作成 CreateUvMorph(morph_manager, morphs, creation_info); //材質モーフ作成 CreateMaterialMorph(morph_manager, morphs, creation_info); //モーフ一覧設定(モーフコンポーネントの情報を拾う為、最後に設定する) morph_manager.morphs = morphs.Select(x=>x.GetComponent<MorphBase>()).ToArray(); //メッシュ・マテリアル設定 morph_manager.renderers = renderers; morph_manager.mesh = mesh; morph_manager.materials = materials; }
/// <summary> /// メッシュを作成する為の情報を作成(複数メッシュ版) /// </summary> /// <returns>メッシュ作成情報</returns> MeshCreationInfo[] CreateMeshCreationInfoMulti() { //マテリアル単位のMeshCreationInfo.Packを作成する MeshCreationInfo.Pack[] packs = CreateMeshCreationInfoPacks(); //頂点数の多い順に並べる(メッシュ分割アルゴリズム上、後半に行く程頂点数が少ない方が敷き詰め効率が良い) System.Array.Sort(packs, (x,y)=>y.vertices.Length - x.vertices.Length); List<MeshCreationInfo> result = new List<MeshCreationInfo>(); do { uint vertex_sum = 0; MeshCreationInfo info = new MeshCreationInfo(); //マテリアルパック作成 info.value = Enumerable.Range(0, packs.Length) .Where(x=>null!=packs[x]) //有効なマテリアルに絞る .Where(x=>{ //採用しても頂点数が限界を超えないなら vertex_sum += (uint)packs[x].vertices.Length; return vertex_sum < c_max_vertex_count_in_mesh; }) .Select(x=>{ //マテリアルの採用と無効化 var pack = packs[x]; packs[x] = null; return pack; }) .ToArray(); //マテリアルインデックスに並べる(メッシュの選定が終わったので見易い様に並びを戻す) System.Array.Sort(info.value, (x,y)=>((x.material_index>y.material_index)? 1: (x.material_index<y.material_index)? -1: 0)); //総頂点作成 info.all_vertices = info.value.SelectMany(x=>x.vertices).Distinct().ToArray(); System.Array.Sort(info.all_vertices); //頂点リアサインインデックス用辞書作成 info.reassign_dictionary = new Dictionary<uint, uint>(); uint reassign_index = 0; foreach (var i in info.all_vertices) { info.reassign_dictionary[i] = reassign_index++; } //戻り値に追加 result.Add(info); } while (packs.Any(x=>null!=x)); //使用していないマテリアルが為るならループ return result.ToArray(); }
/// <summary> /// メッシュ作成 /// </summary> /// <returns>メッシュ</returns> /// <param name='creation_info'>メッシュ作成情報</param> Mesh[] CreateMesh(MeshCreationInfo[] creation_info) { Mesh[] result = new Mesh[creation_info.Length]; for (int i = 0, i_max = creation_info.Length; i < i_max; ++i) { Mesh mesh = new Mesh(); EntryAttributesForMesh(mesh, creation_info[i]); SetSubMesh(mesh, creation_info[i]); CreateAssetForMesh(mesh, i); result[i] = mesh; } return result; }
/// <summary> /// マテリアル作成 /// </summary> /// <returns>マテリアル</returns> /// <param name='creation_info'>メッシュ作成情報</param> Material[][] CreateMaterials(MeshCreationInfo[] creation_info) { Material[][] result = new Material[creation_info.Length][]; for (int i = 0, i_max = creation_info.Length; i < i_max; ++i) { Material[] materials = EntryAttributesForMaterials(creation_info[i]); CreateAssetForMaterials(materials, creation_info[i]); result[i] = materials; } return result; }
/// <summary> /// 1マテリアルの頂点数が1メッシュで表現出来ない場合に分割する /// </summary> /// <returns>メッシュ作成情報のマテリアルパック</returns> /// <param name='creation_infos'>メッシュ作成情報のマテリアルパック</param> MeshCreationInfo.Pack[] SplitSubMesh(MeshCreationInfo.Pack[] packs) { MeshCreationInfo.Pack[] result = packs; if (packs.Any(x=>c_max_vertex_count_in_mesh<=x.vertices.Length)) { //1メッシュに収まらないマテリアルが有るなら List<MeshCreationInfo.Pack> result_list = new List<MeshCreationInfo.Pack>(); foreach (var pack in packs) { if (c_max_vertex_count_in_mesh <= pack.vertices.Length) { //1メッシュに収まらないなら //分離 var split_pack = SplitSubMesh(pack); foreach (var i in split_pack) { result_list.Add(i); } } else { //1メッシュに収まるなら //素通し result_list.Add(pack); } } result = result_list.ToArray(); } return result; }
/// <summary> /// メッシュにサブメッシュを登録する /// </summary> /// <param name='mesh'>対象メッシュ</param> /// <param name='creation_info'>メッシュ作成情報</param> void SetSubMesh(Mesh mesh, MeshCreationInfo creation_info) { // マテリアル対サブメッシュ // サブメッシュとはマテリアルに適用したい面頂点データのこと // 面ごとに設定するマテリアルはここ mesh.subMeshCount = creation_info.value.Length; for (int i = 0, i_max = creation_info.value.Length; i < i_max; ++i) { //format_.face_vertex_list.face_vert_indexを[start](含む)から[start+count](含まず)迄取り出し int[] indices = format_.face_vertex_list.face_vert_index.Skip((int)creation_info.value[i].plane_start) .Take((int)creation_info.value[i].plane_count) .Select(x=>(int)creation_info.reassign_dictionary[x]) //頂点リアサインインデックス変換 .ToArray(); mesh.SetTriangles(indices, i); } }
/// <summary> /// メッシュに基本情報(頂点座標・法線・UV・ボーンウェイト)を登録する /// </summary> /// <param name='mesh'>対象メッシュ</param> /// <param name='creation_info'>メッシュ作成情報</param> void EntryAttributesForMesh(Mesh mesh, MeshCreationInfo creation_info) { mesh.vertices = creation_info.all_vertices.Select(x=>format_.vertex_list.vertex[x].pos * scale_).ToArray(); mesh.normals = creation_info.all_vertices.Select(x=>format_.vertex_list.vertex[x].normal_vec).ToArray(); mesh.uv = creation_info.all_vertices.Select(x=>format_.vertex_list.vertex[x].uv).ToArray(); if (0 < format_.header.additionalUV) { //追加UVが1つ以上有れば //1つ目のみ登録 mesh.uv2 = creation_info.all_vertices.Select(x=>new Vector2(format_.vertex_list.vertex[x].add_uv[0].x, format_.vertex_list.vertex[x].add_uv[0].y)).ToArray(); } mesh.boneWeights = creation_info.all_vertices.Select(x=>ConvertBoneWeight(format_.vertex_list.vertex[x].bone_weight)).ToArray(); mesh.colors = creation_info.all_vertices.Select(x=>new Color(0.0f, 0.0f, 0.0f, format_.vertex_list.vertex[x].edge_magnification * 0.25f)).ToArray(); //不透明度にエッジ倍率を0.25倍した情報を仕込む(0~8迄は表せる) }
/// <summary> /// マテリアルに基本情報(シェーダー・カラー・テクスチャ)を登録する /// </summary> /// <returns>マテリアル</returns> /// <param name='creation_info'>メッシュ作成情報</param> Material[] EntryAttributesForMaterials(MeshCreationInfo creation_info) { return creation_info.value.Select(x=>ConvertMaterial(format_.material_list.material[x.material_index])) .ToArray(); }
/// <summary> /// 頂点モーフ作成 /// </summary> /// <param name='morph_manager'>表情マネージャー</param> /// <param name='morphs'>モーフのゲームオブジェクト</param> /// <param name='creation_info'>メッシュ作成情報</param> void CreateVertexMorph(MorphManager morph_manager, GameObject[] morphs, MeshCreationInfo[] creation_info) { //インデックスと元データの作成 List<uint> original_indices = format_.morph_list.morph_data.Where(x=>(PMXFormat.MorphData.MorphType.Vertex == x.morph_type)) //該当モーフに絞る .SelectMany(x=>x.morph_offset.Select(y=>((PMXFormat.VertexMorphOffset)y).vertex_index)) //インデックスの取り出しと連結 .Distinct() //重複したインデックスの削除 .ToList(); //ソートに向けて一旦リスト化 original_indices.Sort(); //ソート int[] indices = original_indices.Select(x=>(int)x).ToArray(); Vector3[] source = indices.Select(x=>format_.vertex_list.vertex[x].pos * scale_) //インデックスを用いて、元データをパック .ToArray(); //インデックス逆引き用辞書の作成 Dictionary<uint, uint> index_reverse_dictionary = new Dictionary<uint, uint>(); for (uint i = 0, i_max = (uint)indices.Length; i < i_max; ++i) { index_reverse_dictionary.Add((uint)indices[i], i); } //個別モーフスクリプトの作成 VertexMorph[] script = Enumerable.Range(0, format_.morph_list.morph_data.Length) .Where(x=>PMXFormat.MorphData.MorphType.Vertex == format_.morph_list.morph_data[x].morph_type) //該当モーフに絞る .Select(x=>AssignVertexMorph(morphs[x], format_.morph_list.morph_data[x], index_reverse_dictionary)) .ToArray(); //メッシュ別インデックスの作成 int invalid_vertex_index = format_.vertex_list.vertex.Length; MorphManager.VertexMorphPack.Meshes[] multi_indices = new MorphManager.VertexMorphPack.Meshes[creation_info.Length]; for (int i = 0, i_max = creation_info.Length; i < i_max; ++i) { multi_indices[i] = new MorphManager.VertexMorphPack.Meshes(); multi_indices[i].indices = new int[indices.Length]; for (int k = 0, k_max = indices.Length; k < k_max; ++k) { if (creation_info[i].reassign_dictionary.ContainsKey((uint)indices[k])) { //このメッシュで有効なら multi_indices[i].indices[k] = (int)creation_info[i].reassign_dictionary[(uint)indices[k]]; } else { //このメッシュでは無効なら multi_indices[i].indices[k] = invalid_vertex_index; //最大頂点数を設定(uint.MaxValueでは無いので注意) } } } //表情マネージャーにインデックス・元データ・スクリプトの設定 morph_manager.vertex_morph = new MorphManager.VertexMorphPack(multi_indices, source, script); }
/// <summary> /// UV・追加UVモーフ作成 /// </summary> /// <param name='morph_manager'>表情マネージャー</param> /// <param name='morphs'>モーフのゲームオブジェクト</param> /// <param name='creation_info'>メッシュ作成情報</param> void CreateUvMorph(MorphManager morph_manager, GameObject[] morphs, MeshCreationInfo[] creation_info) { for (int morph_type_index = 0, morph_type_index_max = 1 + format_.header.additionalUV; morph_type_index < morph_type_index_max; ++morph_type_index) { //モーフタイプ PMXFormat.MorphData.MorphType morph_type; switch (morph_type_index) { case 0: morph_type = PMXFormat.MorphData.MorphType.Uv; break; case 1: morph_type = PMXFormat.MorphData.MorphType.Adduv1; break; case 2: morph_type = PMXFormat.MorphData.MorphType.Adduv2; break; case 3: morph_type = PMXFormat.MorphData.MorphType.Adduv3; break; case 4: morph_type = PMXFormat.MorphData.MorphType.Adduv4; break; default: throw new System.ArgumentOutOfRangeException(); } //インデックスと元データの作成 List<uint> original_indices = format_.morph_list.morph_data.Where(x=>(morph_type == x.morph_type)) //該当モーフに絞る .SelectMany(x=>x.morph_offset.Select(y=>((PMXFormat.UVMorphOffset)y).vertex_index)) //インデックスの取り出しと連結 .Distinct() //重複したインデックスの削除 .ToList(); //ソートに向けて一旦リスト化 original_indices.Sort(); //ソート int[] indices = original_indices.Select(x=>(int)x).ToArray(); Vector2[] source; if (0 == morph_type_index) { //通常UV source = indices.Select(x=>format_.vertex_list.vertex[x].uv) //インデックスを用いて、元データをパック .Select(x=>new Vector2(x.x, x.y)) .ToArray(); } else { //追加UV source = indices.Select(x=>format_.vertex_list.vertex[x].add_uv[morph_type_index - 1]) //インデックスを用いて、元データをパック .Select(x=>new Vector2(x.x, x.y)) .ToArray(); } //インデックス逆引き用辞書の作成 Dictionary<uint, uint> index_reverse_dictionary = new Dictionary<uint, uint>(); for (uint i = 0, i_max = (uint)indices.Length; i < i_max; ++i) { index_reverse_dictionary.Add((uint)indices[i], i); } //個別モーフスクリプトの作成 UvMorph[] script = Enumerable.Range(0, format_.morph_list.morph_data.Length) .Where(x=>morph_type == format_.morph_list.morph_data[x].morph_type) //該当モーフに絞る .Select(x=>AssignUvMorph(morphs[x], format_.morph_list.morph_data[x], index_reverse_dictionary)) .ToArray(); //メッシュ別インデックスの作成 int invalid_vertex_index = format_.vertex_list.vertex.Length; MorphManager.UvMorphPack.Meshes[] multi_indices = new MorphManager.UvMorphPack.Meshes[creation_info.Length]; for (int i = 0, i_max = creation_info.Length; i < i_max; ++i) { multi_indices[i] = new MorphManager.UvMorphPack.Meshes(); multi_indices[i].indices = new int[indices.Length]; for (int k = 0, k_max = indices.Length; k < k_max; ++k) { if (creation_info[i].reassign_dictionary.ContainsKey((uint)indices[k])) { //このメッシュで有効なら multi_indices[i].indices[k] = (int)creation_info[i].reassign_dictionary[(uint)indices[k]]; } else { //このメッシュでは無効なら multi_indices[i].indices[k] = invalid_vertex_index; //最大頂点数を設定(uint.MaxValueでは無いので注意) } } } //表情マネージャーにインデックス・元データ・スクリプトの設定 morph_manager.uv_morph[morph_type_index] = new MorphManager.UvMorphPack(multi_indices, source, script); } }
/// <summary> /// マテリアル作成 /// </summary> /// <returns>マテリアル</returns> /// <param name='creation_info'>メッシュ作成情報</param> Material[][] CreateMaterials(MeshCreationInfo[] creation_info) { // 適当なフォルダに投げる string path = format_.meta_header.folder + "/Materials/"; if (!System.IO.Directory.Exists(path)) { AssetDatabase.CreateFolder(format_.meta_header.folder, "Materials"); } //全マテリアルを作成 Material[] materials = EntryAttributesForMaterials(); CreateAssetForMaterials(materials); //メッシュ単位へ振り分け Material[][] result = new Material[creation_info.Length][]; for (int i = 0, i_max = creation_info.Length; i < i_max; ++i) { result[i] = creation_info[i].value.Select(x=>materials[x.material_index]).ToArray(); } return result; }
/// <summary> /// 材質モーフ作成 /// </summary> /// <param name='morph_manager'>表情マネージャー</param> /// <param name='morphs'>モーフのゲームオブジェクト</param> /// <param name='creation_info'>メッシュ作成情報</param> void CreateMaterialMorph(MorphManager morph_manager, GameObject[] morphs, MeshCreationInfo[] creation_info) { //インデックスと元データの作成 List<uint> original_indices = format_.morph_list.morph_data.Where(x=>(PMXFormat.MorphData.MorphType.Material == x.morph_type)) //該当モーフに絞る .SelectMany(x=>x.morph_offset.Select(y=>((PMXFormat.MaterialMorphOffset)y).material_index)) //インデックスの取り出しと連結 .Distinct() //重複したインデックスの削除 .ToList(); //ソートに向けて一旦リスト化 original_indices.Sort(); //ソート if (uint.MaxValue == original_indices.LastOrDefault()) { //最後が uint.MaxValue(≒-1) なら //全材質対象が存在するので全インデックスを取得 original_indices = Enumerable.Range(0, format_.material_list.material.Length + 1).Select(x=>(uint)x).ToList(); original_indices[format_.material_list.material.Length] = uint.MaxValue; //uint.MaxValueを忘れない } int[] indices = original_indices.Select(x=>(int)x).ToArray(); MaterialMorph.MaterialMorphParameter[] source = indices.Where(x=>x<format_.material_list.material.Length) .Select(x=>{ //インデックスを用いて、元データをパック MaterialMorph.MaterialMorphParameter result = new MaterialMorph.MaterialMorphParameter(); if (0 <= x) { //-1(全材質対象)で無いなら //元データを取得 PMXFormat.Material y = format_.material_list.material[x]; result.color = y.diffuse_color; result.specular = new Color(y.specular_color.r, y.specular_color.g, y.specular_color.b, y.specularity); result.ambient = y.ambient_color; result.outline_color = y.edge_color; result.outline_width = y.edge_size; result.texture_color = Color.white; result.sphere_color = Color.white; result.toon_color = Color.white; } else { //-1(全材質対象)なら //適当にでっち上げる result = MaterialMorph.MaterialMorphParameter.zero; } return result; }) .ToArray(); //インデックス逆引き用辞書の作成 Dictionary<uint, uint> index_reverse_dictionary = new Dictionary<uint, uint>(); for (uint i = 0, i_max = (uint)indices.Length; i < i_max; ++i) { index_reverse_dictionary.Add((uint)indices[i], i); } //個別モーフスクリプトの作成 MaterialMorph[] script = Enumerable.Range(0, format_.morph_list.morph_data.Length) .Where(x=>PMXFormat.MorphData.MorphType.Material == format_.morph_list.morph_data[x].morph_type) //該当モーフに絞る .Select(x=>AssignMaterialMorph(morphs[x], format_.morph_list.morph_data[x], index_reverse_dictionary)) .ToArray(); //材質リアサイン辞書の作成 Dictionary<uint, uint>[] material_reassign_dictionary = new Dictionary<uint, uint>[creation_info.Length + 1]; for (int i = 0, i_max = creation_info.Length; i < i_max; +++i) { material_reassign_dictionary[i] = new Dictionary<uint, uint>(); for (uint k = 0, k_max = (uint)creation_info[i].value.Length; k < k_max; ++k) { material_reassign_dictionary[i][creation_info[i].value[k].material_index] = k; } if (-1 == indices.LastOrDefault()) { //indices の最後が -1(≒uint.MaxValue) なら //全材質対象が存在するので材質リアサイン辞書に追加 material_reassign_dictionary[i][uint.MaxValue] = uint.MaxValue; } } //メッシュ別インデックスの作成 int invalid_material_index = format_.material_list.material.Length; MorphManager.MaterialMorphPack.Meshes[] multi_indices = new MorphManager.MaterialMorphPack.Meshes[creation_info.Length]; for (int i = 0, i_max = creation_info.Length; i < i_max; ++i) { multi_indices[i] = new MorphManager.MaterialMorphPack.Meshes(); multi_indices[i].indices = new int[indices.Length]; for (int k = 0, k_max = indices.Length; k < k_max; ++k) { if (material_reassign_dictionary[i].ContainsKey((uint)indices[k])) { //この材質で有効なら multi_indices[i].indices[k] = (int)material_reassign_dictionary[i][(uint)indices[k]]; } else { //この材質では無効なら multi_indices[i].indices[k] = invalid_material_index; //最大材質数を設定(uint.MaxValueでは無いので注意) } } } //表情マネージャーにインデックス・元データ・スクリプトの設定 morph_manager.material_morph = new MorphManager.MaterialMorphPack(multi_indices, source, script); }
/// <summary> /// Gets the thumbnail image /// </summary> /// <param name="width">The width of the image that should be returned.</param> /// <returns> /// The image for the thumbnail /// </returns> protected override Bitmap GetThumbnailImage(uint width) { // Attempt to open the stream with a reader var pmx = PMXLoaderScript.Import(SelectedItemPath); MeshCreationInfo creation_info = CreateMeshCreationInfoSingle(pmx); var diffuseMat = MaterialHelper.CreateMaterial(Colors.Gray); var models = new Model3DGroup(); for (int i = 0, i_max = creation_info.value.Length; i < i_max; ++i) { int[] indices = creation_info.value[i].plane_indices.Select(x => (int)creation_info.reassign_dictionary[x]) .ToArray(); var mesh = new MeshGeometry3D { Positions = new Point3DCollection(pmx.vertex_list.vertex.Select(x => x.pos)), TextureCoordinates = new PointCollection(pmx.vertex_list.vertex.Select(x => new System.Windows.Point(x.uv.X, x.uv.Y))) }; indices.ToList() .ForEach(x => mesh.TriangleIndices.Add(x)); var textureIndex = pmx.material_list.material[creation_info.value[i].material_index].usually_texture_index; var texturePath = pmx.texture_list.texture_file.ElementAtOrDefault((int)textureIndex); var material = diffuseMat; if (!string.IsNullOrWhiteSpace(texturePath)) { texturePath = Path.Combine(Path.GetDirectoryName(SelectedItemPath), texturePath); //Log($"Texture found: {texturePath}"); if (!string.IsNullOrWhiteSpace(texturePath) && File.Exists(texturePath)) { // dds and tga if (new string[] { ".dds", ".tga" }.Any(x => x.Equals(Path.GetExtension(texturePath)))) { var bitmap = PFimToBitmap(texturePath); material = MaterialHelper.CreateImageMaterial(Bitmap2BitmapImage(bitmap), 1); } else { material = MaterialHelper.CreateImageMaterial(BitmapImageFromFile(texturePath), 1); } } } models.Children.Add(new GeometryModel3D(mesh, material)); } var sorting = new SortingVisual3D() { Content = models }; var view = new HelixViewport3D(); view.Children.Add(sorting); view.Camera.Position = new Point3D(0, 15, -30); view.Camera.LookDirection = new Vector3D(0, -5, 30); view.Background = System.Windows.Media.Brushes.Transparent; view.Children.Add(new SunLight() { Altitude = 260 }); view.Children.Add(new DefaultLights()); try { var bitmap = view.Viewport.RenderBitmap(width, width, new SolidColorBrush(Colors.Transparent)); view.Children.Clear(); view = null; sorting = null; models = null; GC.Collect(); return(BitmapFromSource(bitmap)); } catch (Exception exception) { view.Children.Clear(); view = null; sorting = null; models = null; GC.Collect(); LogError("An exception occurred Rendering bitmap.", exception); //MessageBox.Show(exception.Message); //MessageBox.Show(exception.StackTrace); return(null); } }