public static void アニメーションを追加する(string vmdFilePath, PMXモデル PMXモデル, bool すべての親を無視する = true) { var vmd = new VMDFormat.モーション(vmdFilePath); ボーンモーションを追加する(vmd.ボーンフレームリスト, PMXモデル, すべての親を無視する); モーフを追加する(vmd.モーフフレームリスト, PMXモデル); }
/// <summary> /// モデルファイルを開く /// </summary> /// <param name="filePath">PMXのファイルパス</param> /// <param name="loader">テクスチャのパス解決インターフェース</param> /// <returns>MMDModelのインスタンス</returns> public static PMXModel ファイルから開く(string filePath, サブリソースローダー loader) { using (FileStream fs = File.OpenRead(filePath)) { return(new PMXModel(PMXモデル.読み込む(fs), loader, Path.GetFileName(filePath))); } }
private void _LoadBones(PMXモデル model) { for (int i = 0; i < model.ボーンリスト.Count; i++) { if (model.ボーンリスト[i].親ボーンのインデックス == -1) { ボーンのルート.Add(new PMXボーン(model.ボーンリスト, i, 0, this)); } } var comparison = new Comparison <PMXボーン>((x, y) => { // 後であればあるほどスコアが大きくなるように計算する int xScore = 0; int yScore = 0; int BoneCount = model.ボーンリスト.Count; if (x.形階層の物理前後 == 形階層の物理前後指定種別.物理演算後) { xScore += BoneCount * BoneCount; } if (y.形階層の物理前後 == 形階層の物理前後指定種別.物理演算後) { yScore += BoneCount * BoneCount; } xScore += BoneCount * x.形階層; yScore += BoneCount * y.形階層; xScore += x.ボーンインデックス; yScore += y.ボーンインデックス; return(xScore - yScore); }); IKボーンリスト.Sort(comparison); ボーンのルート.Sort(comparison); }
/// <summary> /// VMDのモーフフレームリストからアニメ変数を構築する。 /// </summary> /// <param name="VMDFモーフフレームリスト">入力となるモーフフレームリスト。</param> /// <param name="PMXモデル">対象となるPMXモデル。</param> public static void モーフを追加する(VMDFormat.モーフフレームリスト VMDFモーフフレームリスト, PMXモデル PMXモデル) { // すべてのモーフについて…… for (int i = 0; i < PMXモデル.モーフリスト.Length; i++) { var pmxMorph = PMXモデル.モーフリスト[i]; // 同じモーフ名のフレームを列挙する。 var morphFrames = VMDFモーフフレームリスト .Where((frame) => (frame.モーフ名 == pmxMorph.PMXFモーフ.モーフ名)) // 同じ名前のフレームを、 .OrderBy((frame) => frame.フレーム番号); // フレーム番号昇順に。 // 列挙されたすべてのフレームについて…… uint 前のフレーム番号 = 0; foreach (var frame in morphFrames) { var 持続時間sec = (frame.フレーム番号 - 前のフレーム番号) / 30.0; // 1frame = 1/30sec pmxMorph.アニメ変数_モーフ.遷移を追加する(new リニア実数アニメ遷移(frame.モーフ値, 持続時間sec)); 前のフレーム番号 = frame.フレーム番号; } } }
public PMXスケルトン物理変形付き(PMXモデル model) : base(model) { _物理変形管理 = new PMX物理変形更新(ボーン配列, model.剛体リスト, model.ジョイントリスト); 形更新リスト.Add(_物理変形管理); }
public void 初期化する(PMXモデル model, モーフ管理 morph, スキニング skinning, バッファ管理 bufferManager) { _スキニング = skinning; _Stopwatch = new Stopwatch(); _Stopwatch.Start(); _モーフ管理 = morph; モーションリスト = new List <KeyValuePair <string, モーション> >(); }
/// <summary> /// コンストラクタ。 /// 初期化だけ行い、読み込み(Load)は行わない。 /// </summary> public PMXModel(PMXモデル modeldata, サブリソースローダー subResourceLoader, string filename) { モデル = modeldata; サブリソースローダー = subResourceLoader; モデル状態 = new モデル状態既定実装(); サブセット管理 = new PMXサブセット管理(this, modeldata); トゥーン管理 = new PMXトゥーンテクスチャ管理(); セルフシャドウ色 = new Vector4(0, 0, 0, 1); 地面影色 = new Vector4(0, 0, 0, 1); ファイル名 = filename; 表示中 = true; }
public PMXスケルトン(PMXモデル model) { // ボーンの数だけ初期化 ボーン配列 = new PMXボーン[model.ボーンリスト.Count]; ボーンのモデルポーズ配列 = new Matrix[model.ボーンリスト.Count]; ボーンのローカル位置 = new Vector3[model.ボーンリスト.Count]; ボーンの回転 = new Vector4[model.ボーンリスト.Count]; IKボーンリスト = new List <PMXボーン>(); // ボーンを読み込む _LoadBones(model); // ボーンマップ作製 ボーンマップ = new Dictionary <string, PMXボーン>(); foreach (var bone in ボーン配列) { if (ボーンマップ.ContainsKey(bone.ボーン名)) { int i = 0; do { i++; } while(ボーンマップ.ContainsKey(bone.ボーン名 + i.ToString())); ボーンマップ.Add(bone.ボーン名 + i.ToString(), bone); Debug.WriteLine("ボーン名{0}は重複しています。自動的にボーン名{1}と読み替えられました。", bone.ボーン名, bone.ボーン名 + i); } else { ボーンマップ.Add(bone.ボーン名, bone); } } // 変形更新プロバイダリスト作成 形更新リスト = new List <形更新>(); 形更新リスト.Add(new CCDによるIK変形更新(new WeakReference <List <PMXボーン> >(IKボーンリスト))); 形更新リスト.Add(new 親付与によるFK変形更新(ボーン配列)); if (ボーン配列.Length > 768) { throw new InvalidOperationException("MMFでは現在768以上のボーンを持つモデルについてサポートしていません。\nただし、Resource\\Shader\\DefaultShader.fx内のボーン変形行列の配列float4x4 BoneTrans[512]:BONETRANS;の要素数を拡張しこの部分をコメントアウトすれば暫定的に利用することができるかもしれません。"); } }
/// <summary> /// VMDのボーンフレームリストからアニメ変数を構築する。 /// </summary> /// <param name="VMDFボーンフレームリスト">入力となるボーンフレームリスト。</param> /// <param name="PMXモデル">対象となるPMXモデル。</param> public static void ボーンモーションを追加する(VMDFormat.ボーンフレームリスト VMDFボーンフレームリスト, PMXモデル PMXモデル, bool 全ての親を無視する = true) { // すべてのPMXボーンについて…… for (int i = 0; i < PMXモデル.ボーンリスト.Length; i++) { var pmxBone = PMXモデル.ボーンリスト[i]; if (全ての親を無視する && pmxBone.PMXFボーン.ボーン名 == "全ての親") { continue; } // 同じボーン名のフレームを列挙する。 var boneFrames = VMDFボーンフレームリスト .Where((frame) => (frame.ボーン名 == pmxBone.PMXFボーン.ボーン名)) // 同じボーン名のフレームを、 .OrderBy((frame) => frame.フレーム番号); // フレーム番号昇順に。 // 列挙されたすべてのフレームについて…… uint 前のフレーム番号 = 0; foreach (var frame in boneFrames) { var 持続時間sec = (frame.フレーム番号 - 前のフレーム番号) / 30.0; // 1frame = 1/30sec pmxBone.アニメ変数_移動.遷移を追加する( new ベジェ移動アニメ遷移(frame.ボーンの位置, 持続時間sec, frame.ベジェ曲線[0], frame.ベジェ曲線[1], frame.ベジェ曲線[2])); pmxBone.アニメ変数_回転.遷移を追加する( new ベジェ回転アニメ遷移(frame.ボーンの回転, 持続時間sec, frame.ベジェ曲線[3])); 前のフレーム番号 = frame.フレーム番号; } } }
private void _モーフを適用する(float 現在値, PMXモデル PMXモデル, PMXモーフ制御 適用対象モーフ) { switch (適用対象モーフ.PMXFモーフ.モーフ種類) { case PMXFormat.モーフ種別.頂点: #region " 頂点モーフ " //---------------- { foreach (PMXFormat.頂点モーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].Position.X += offset.座標オフセット量.X * 現在値; PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].Position.Y += offset.座標オフセット量.Y * 現在値; PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].Position.Z += offset.座標オフセット量.Z * 現在値; PMXモデル.PMX頂点制御.頂点の変更を通知する((int)offset.頂点インデックス); } } //---------------- #endregion break; case PMXFormat.モーフ種別.UV: #region " UVモーフ " //---------------- { foreach (PMXFormat.UVモーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].UV += new Vector2(offset.UVオフセット量.X, offset.UVオフセット量.Y) * 現在値; PMXモデル.PMX頂点制御.頂点の変更を通知する((int)offset.頂点インデックス); } } //---------------- #endregion break; case PMXFormat.モーフ種別.追加UV1: #region " 追加UV1モーフ " //---------------- { foreach (PMXFormat.UVモーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].AddUV1 += offset.UVオフセット量 * 現在値; PMXモデル.PMX頂点制御.頂点の変更を通知する((int)offset.頂点インデックス); } } //---------------- #endregion break; case PMXFormat.モーフ種別.追加UV2: #region " 追加UV2モーフ " //---------------- { foreach (PMXFormat.UVモーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].AddUV2 += offset.UVオフセット量 * 現在値; PMXモデル.PMX頂点制御.頂点の変更を通知する((int)offset.頂点インデックス); } } //---------------- #endregion break; case PMXFormat.モーフ種別.追加UV3: #region " 追加UV3モーフ " //---------------- { foreach (PMXFormat.UVモーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].AddUV3 += offset.UVオフセット量 * 現在値; PMXモデル.PMX頂点制御.頂点の変更を通知する((int)offset.頂点インデックス); } } //---------------- #endregion break; case PMXFormat.モーフ種別.追加UV4: #region " 追加UV4モーフ " //---------------- { foreach (PMXFormat.UVモーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { PMXモデル.PMX頂点制御.入力頂点配列[offset.頂点インデックス].AddUV4 += offset.UVオフセット量 * 現在値; PMXモデル.PMX頂点制御.頂点の変更を通知する((int)offset.頂点インデックス); } } //---------------- #endregion break; case PMXFormat.モーフ種別.ボーン: #region " ボーンモーフ " //---------------- { foreach (PMXFormat.ボーンモーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { var bone = PMXモデル.ボーンリスト[offset.ボーンインデックス]; bone.移動 += offset.移動量 * 現在値; bone.回転 *= new Quaternion( offset.回転量.X * 現在値, offset.回転量.Y * 現在値, offset.回転量.Z * 現在値, offset.回転量.W * 現在値); } } //---------------- #endregion break; case PMXFormat.モーフ種別.材質: #region " 材質モーフ " //---------------- { // todo: 材質モーフ・テクスチャ係数への対応 // todo: 材質モーフ・スフィアテクスチャ係数への対応 // todo: 材質モーフ・Toonテクスチャ係数への対応 foreach (PMXFormat.材質モーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { if (offset.材質インデックス == -1) // -1:全材質が対象 { foreach (var 材質 in PMXモデル.材質リスト) { 差分セット(offset, 材質); } } else { var 材質 = PMXモデル.材質リスト[offset.材質インデックス]; 差分セット(offset, 材質); } } void 差分セット(PMXFormat.材質モーフオフセット offset, PMX材質制御 材質) { switch (offset.オフセット演算形式) { case 0: // 乗算 材質.乗算差分.拡散色 += offset.拡散色 * 現在値; 材質.乗算差分.反射色 += offset.反射色 * 現在値; 材質.乗算差分.反射強度 += offset.反射強度 * 現在値; 材質.乗算差分.環境色 += offset.環境色 * 現在値; 材質.乗算差分.エッジ色 += offset.エッジ色 * 現在値; 材質.乗算差分.エッジサイズ += offset.エッジサイズ * 現在値; break; case 1: // 加算 材質.加算差分.拡散色 += offset.拡散色 * 現在値; 材質.加算差分.反射色 += offset.反射色 * 現在値; 材質.加算差分.反射強度 += offset.反射強度 * 現在値; 材質.加算差分.環境色 += offset.環境色 * 現在値; 材質.加算差分.エッジ色 += offset.エッジ色 * 現在値; 材質.加算差分.エッジサイズ += offset.エッジサイズ * 現在値; break; } } } //---------------- #endregion break; case PMXFormat.モーフ種別.グループ: #region " グループモーフ " //---------------- { foreach (PMXFormat.グループモーフオフセット offset in 適用対象モーフ.PMXFモーフ.モーフオフセットリスト) { var メンバモーフ = PMXモデル.モーフリスト[offset.モーフインデックス]; if (メンバモーフ.PMXFモーフ.モーフ種類 == PMXFormat.モーフ種別.グループ) { throw new InvalidOperationException("グループモーフのグループとしてグループモーフが指定されています。"); } this._モーフを適用する(現在値 * offset.影響度, PMXモデル, メンバモーフ); } } //---------------- #endregion break; case PMXFormat.モーフ種別.フリップ: // todo: フリップモーフの実装 break; case PMXFormat.モーフ種別.インパルス: // todo: インパルスモーフの実装 break; } }
// 更新 internal void モーフを適用する(double 現在時刻sec, PMXモデル PMXモデル) { var 現在値 = TranslatedMorphValue + this.アニメ変数_モーフ.更新する(現在時刻sec); this._モーフを適用する(現在値 > 1 ? 1 : (現在値 < 0 ? 0 : 現在値), PMXモデル, this); }
// 生成と終了 public PMXモデルパス(PMXモデル model) { this._オブジェクト = model; }
public PMXModel物理変形付き(PMXモデル modeldata, サブリソースローダー subResourceLoader, string filename) : base(modeldata, subResourceLoader, filename) { }
// 更新 internal void モーフを適用する(double 現在時刻sec, PMXモデル PMXモデル) { var 現在値 = this.アニメ変数_モーフ.更新する(現在時刻sec); this._モーフを適用する(現在値, PMXモデル, this); }
public PMXサブセット管理(PMXModel drawable, PMXモデル model) { _モデル = model; Drawable = drawable; }