/// <summary> /// 材質モーフ計算 /// </summary> void ComputeMaterialMorph() { if (0 < material_morph.meshes.Length) { //各材質を初期化しておく MaterialMorph.MaterialMorphParameter[] composite_mul = Enumerable.Repeat(MaterialMorph.MaterialMorphParameter.one, material_morph.source.Length).ToArray(); MaterialMorph.MaterialMorphParameter[] composite_add = Enumerable.Repeat(MaterialMorph.MaterialMorphParameter.zero, material_morph.source.Length).ToArray(); // 表情ごとに計算する bool is_update = false; foreach (var morph in material_morph.script) { if (morph.Compute(composite_mul, composite_add)) { is_update = true; } } if (is_update) { //全材質計算 bool has_all_target = false; if (-1 == material_morph.meshes[0].indices.LastOrDefault()) { //最後に-1(≒uint.MaxValue)が有れば //全材質モーフが有る has_all_target = true; } if (has_all_target) { //全材質モーフが有れば //全材質に反映 MaterialMorph.MaterialMorphParameter composite_mul_all = composite_mul.Last(); MaterialMorph.MaterialMorphParameter composite_add_all = composite_add.Last(); for (int i = 0, i_max = material_morph.source.Length - 1; i < i_max; ++i) { composite_mul[i] *= composite_mul_all; composite_add[i] += composite_add_all; } } // ここで計算結果を入れていく for (int r = 0, r_max = renderers.Length; r < r_max; ++r) { for (int m = 0, m_max = material_morph.source.Length - ((has_all_target)? 1: 0); m < m_max; ++m) { int index = material_morph.meshes[r].indices[m]; if (index < renderer_shared_materials_[r].Length) { ApplyMaterialMorph(renderer_shared_materials_[r][index] , material_morph.source[m] , composite_mul[m] , composite_add[m] ); } } } } } }
/// <summary> /// 材質モーフ反映 /// </summary> /// <param name='material'>反映先マテリアル</param> /// <param name='composite'>反映するデータ</param> private static void ApplyMaterialMorph(Material material, MaterialMorph.MaterialMorphParameter source, MaterialMorph.MaterialMorphParameter composite_mul, MaterialMorph.MaterialMorphParameter composite_add) { MaterialMorph.MaterialMorphParameter composite = source * composite_mul + composite_add; material.SetColor("_Color", composite.color); material.SetFloat("_Opacity", composite.color.a); material.SetColor("_AmbColor", composite.ambient); material.SetColor("_SpecularColor", composite.specular); material.SetFloat("_Shininess", composite.specular.a); material.SetColor("_OutlineColor", composite.outline_color); material.SetFloat("_OutlineWidth", composite.outline_width); #if MFU_CHANGEABLE_TEXTURE_COLOR_SHADER //テクスチャカラーの変更出来るシェーダーが無いので無効化 material.SetColor("_MainTexColor", composite.texture_color); material.SetColor("_SphereTexColor", composite.sphere_color); material.SetColor("_ToonTexColor", composite.toon_color); #endif //MFU_CHANGEABLE_TEXTURE_COLOR_SHADER }
/// <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> /// 材質モーフ設定 /// </summary> /// <returns>材質モーフスクリプト</returns> /// <param name='morph'>モーフのゲームオブジェクト</param> /// <param name='data'>PMX用モーフデータ</param> /// <param name='index_reverse_dictionary'>インデックス逆引き用辞書</param> MaterialMorph AssignMaterialMorph(GameObject morph, PMXFormat.MorphData data, Dictionary<uint, uint> index_reverse_dictionary) { MaterialMorph result = morph.AddComponent<MaterialMorph>(); result.panel = (MorphManager.PanelType)data.handle_panel; result.indices = data.morph_offset.Select(x=>((PMXFormat.MaterialMorphOffset)x).material_index) //インデックスを取り出し .Select(x=>(int)index_reverse_dictionary[x]) //逆変換を掛ける .ToArray(); result.values = data.morph_offset.Select(x=>{ PMXFormat.MaterialMorphOffset y = (PMXFormat.MaterialMorphOffset)x; MaterialMorph.MaterialMorphParameter param = new MaterialMorph.MaterialMorphParameter(); param.color = y.diffuse; param.specular = new Color(y.specular.r, y.specular.g, y.specular.b, y.specularity); param.ambient = y.ambient; param.outline_color = y.edge_color; param.outline_width = y.edge_size; param.texture_color = y.texture_coefficient; param.sphere_color = y.sphere_texture_coefficient; param.toon_color = y.toon_texture_coefficient; return param; }) .ToArray(); result.operation = data.morph_offset.Select(x=>(MaterialMorph.OperationType)((PMXFormat.MaterialMorphOffset)x).offset_method) .ToArray(); return result; }