public static MMDMotion2 bake(MMDMotion2 motion, MMDModel1 model) { //ボーン取得 MMDBoneManager boneManager = ModelConverter.BuildBoneManager(model); //ベイク前のモーションとベイク後のモーションを準備 MMDMotion beforeMotion = MotionConverter.Convert(motion); MMDMotion afterMotion = CreateAfterMotionPrototype(beforeMotion, boneManager); //アニメーションプレイヤーを作成 AnimationPlayer player = new AnimationPlayer(boneManager); player.SetMotion(beforeMotion); //ベイクしていく uint frameNo = 0; bool ExitFlag = false; while (!ExitFlag) { ExitFlag = !player.Update(); //ボーンのグローバル行列更新 boneManager.CalcGlobalTransform(); //IK更新 boneManager.CalcIK(); //ベイク boneManager.bake(frameNo, afterMotion); ++frameNo; } //元のMMDMotion2に直して返却 return(MotionConverter.Convert(afterMotion, motion.ModelName)); }
public AnimationPlayer(MMDBoneManager boneManager) { this.boneManager = boneManager; BindPoses = new Dictionary <string, SQTTransform>(); for (int i = 0; i < boneManager.Count; ++i) { BindPoses.Add(boneManager[i].Name, boneManager[i].BindPose); } }
internal AnimationPlayer(MMDBoneManager bones, IMMDFaceManager faces) { boneManager = bones; faceManager = faces; BindPoses = new Dictionary<string, SQTTransform>(); for (int i = 0; i < boneManager.Count; ++i) { BindPoses.Add(boneManager[i].Name, boneManager[i].BindPose); } Poses = new Dictionary<string, SQTTransform>(BindPoses.Count); Faces = new Dictionary<string, float>(faces.Count); }
/// <summary> /// コンストラクタ /// </summary> /// <param name="modelParts">モデルパーツ</param> /// <param name="boneManager">ボーンマネージャ</param> /// <param name="faceManager">表情マネージャ</param> /// <param name="attachedMotion">付属モーション</param> /// <param name="rigids">剛体</param> /// <param name="joints">ジョイント</param> public MMDXModel(List<IMMDModelPart> modelParts, MMDBoneManager boneManager, IMMDFaceManager faceManager, Dictionary<string, MMDMotion> attachedMotion, MMDRigid[] rigids, MMDJoint[] joints) : base(modelParts, boneManager, faceManager, attachedMotion, rigids, joints) { #if XBOX //ボーンマネージャ・表情マネージャを変換しておく this.boneManager = (MMDXBoxBoneManager)boneManager; this.faceManager = (MMDXBoxFaceManager)faceManager; //グラフィックデバイスの抜き出し if (modelParts.Count > 0) { GraphicsDevice graphics = ((MMDModelPart)modelParts[0]).GraphicsDevice; //頂点バッファの作成 skinVertexBuffer = new WritableVertexBuffer(graphics, this.boneManager.SKinTransformXBox.Length * 4, typeof(VertexSkinning)); this.faceManager.SetUp(graphics); } #endif }
/// <summary> /// コンストラクタ /// </summary> /// <param name="vertex">頂点データ</param> /// <param name="modelParts">モデルパーツ</param> /// <param name="boneManager">ボーンマネージャ</param> /// <param name="faceManager">表情マネージャ</param> /// <param name="attachedMotion">付随モーション</param> /// <param name="rigids">剛体情報</param> /// <param name="joints">関節情報</param> public SlimMMDModel(MMDVertexNmTx[] vertex, List<IMMDModelPart> modelParts, MMDBoneManager boneManager, MMDFaceManager faceManager, Dictionary<string, MMDMotion> attachedMotion, MMDRigid[] rigids, MMDJoint[] joints) : base(modelParts, boneManager, faceManager, attachedMotion, rigids, joints) { m_vertex = vertex; //データのコピー verticesSource = new VertexPNmTx[m_vertex.LongLength]; for (long i = 0; i < m_vertex.LongLength; ++i) { verticesSource[i].Position = m_vertex[i].Position; verticesSource[i].Normal = m_vertex[i].Normal; verticesSource[i].Texture = m_vertex[i].TextureCoordinate; } InitGraphicsResource(); SlimMMDXCore.Instance.LostDevice += OnLostDevice; SlimMMDXCore.Instance.ResetDevice += OnResetDevice; }
/// <summary> /// コンストラクタ /// </summary> /// <param name="modelParts">モデルパーツ</param> /// <param name="boneManager">ボーンマネージャ</param> /// <param name="faceManager">表情マネージャ</param> /// <param name="attachedMotion">付随モーション</param> /// <param name="rigids">剛体情報</param> /// <param name="joints">関節情報</param> public MMDModel(List<IMMDModelPart> modelParts, MMDBoneManager boneManager, IMMDFaceManager faceManager, Dictionary<string, MMDMotion> attachedMotion, MMDRigid[] rigids, MMDJoint[] joints) { Transform = Matrix.Identity; this.modelParts = modelParts; this.boneManager = boneManager; this.faceManager = faceManager; this.attachedMotion = attachedMotion; Culling = true; boneManager.CalcGlobalTransform(); this.physicsManager = new PhysicsManager(rigids, joints, this); foreach (var part in modelParts) part.SetModel(this); Parts = new ReadOnlyCollection<IMMDModelPart>(modelParts); animationPlayer = new AnimationPlayer(boneManager, faceManager); //イベントフック MMDCore.Instance.OnBoneUpdate += new Action<float>(BoneUpdate); MMDCore.Instance.OnSkinUpdate += new Action<float>(SkinUpdate); }
private static MMDMotion CreateAfterMotionPrototype(MMDMotion beforeMotion, MMDBoneManager boneManager) { //ベイク対象外の情報をコピー MMDMotion result = new MMDMotion(); //表情は参照をコピーしておく result.FaceFrames = beforeMotion.FaceFrames; //ボーンは必要分だけ参照をコピー result.BoneFrames = new Dictionary <string, List <MMDBoneKeyFrame> >(); foreach (KeyValuePair <string, List <MMDBoneKeyFrame> > boneSet in beforeMotion.BoneFrames) { if (!boneManager.IsUnderIK(boneSet.Key)) { result.BoneFrames.Add(boneSet.Key, boneSet.Value); } else { result.BoneFrames.Add(boneSet.Key, new List <MMDBoneKeyFrame>()); } } return(result); }
/// <summary> /// IKのソルブ /// </summary> /// <param name="ik">対象IK</param> /// <param name="BoneManager">ボーンマネージャ</param> /// <returns>呼び出し側でUpdateGlobalをもう一度呼ぶ場合はtrue</returns> public bool Solve(MMDIK ik, MMDBoneManager BoneManager) { #if SlimDX Vector4 localTargetPos = Vector4.Zero; Vector4 localEffectorPos = Vector4.Zero; #else Vector3 localTargetPos = Vector3.Zero; Vector3 localEffectorPos = Vector3.Zero; #endif //エフェクタとなるボーンを取得 MMDBone effector = ik.IKTargetBone; //IK対象のボーンのGlobalを更新(別のIK影響下のボーンからIKチェインが出ている場合があるので) Matrix local; for (int i = ik.IKChildBones.Count - 1; i >= 0; --i) {//順番に親子関係になっている。(Processorでチェックかけてある //GlobalTransformを仮更新 int parentBone = ik.IKChildBones[i].SkeletonHierarchy; ik.IKChildBones[i].LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[parentBone].GlobalTransform, out ik.IKChildBones[i].GlobalTransform); } effector.LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[effector.SkeletonHierarchy].GlobalTransform, out effector.GlobalTransform); //ターゲット位置の取得 Vector3 targetPos; Matrix.GetTranslation(ref ik.IKBone.GlobalTransform, out targetPos); //最大ループ回数分ループ for (int it = 0; it < ik.Iteration; ++it) { for (int nodeIndex = 0; nodeIndex < ik.IKChildBones.Count; ++nodeIndex) {//子ノードを子から順番に…… MMDBone node = ik.IKChildBones[nodeIndex]; //エフェクタの位置 Vector3 effectorPos; Matrix.GetTranslation(ref effector.GlobalTransform, out effectorPos); // 注目ノードの位置の取得 Vector3 jointPos; Matrix.GetTranslation(ref node.GlobalTransform, out jointPos); // ワールド座標系から注目ノードの局所座標系への変換 Matrix invCoord; Matrix.Invert(ref node.GlobalTransform, out invCoord); // 各ベクトルの座標変換を行い、検索中のボーンi基準の座標系にする // (1) 注目ノード→エフェクタ位置へのベクトル(a)(注目ノード) Vector3.Transform(ref effectorPos, ref invCoord, out localEffectorPos); // (2) 基準関節i→目標位置へのベクトル(b)(ボーンi基準座標系) Vector3.Transform(ref targetPos, ref invCoord, out localTargetPos); #if SlimDX //念のため…… // (1) 基準関節→エフェクタ位置への方向ベクトル Vector3 basis2Effector = Vector3.Normalize(new Vector3(localEffectorPos.X, localEffectorPos.Y, localEffectorPos.Z)); // (2) 基準関節→目標位置への方向ベクトル Vector3 basis2Target = Vector3.Normalize(new Vector3(localTargetPos.X, localTargetPos.Y, localTargetPos.Z)); #else // (1) 基準関節→エフェクタ位置への方向ベクトル Vector3 basis2Effector = Vector3.Normalize(localEffectorPos); // (2) 基準関節→目標位置への方向ベクトル Vector3 basis2Target = Vector3.Normalize(localTargetPos); #endif // 回転角 float rotationDotProduct = (float)Vector3.Dot(basis2Effector, basis2Target); float rotationAngle = (float)Math.Acos(rotationDotProduct); //回転量制限をかける if (rotationAngle > MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1)) { rotationAngle = MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1); } if (rotationAngle < -MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1)) { rotationAngle = -MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1); } // 回転軸 Vector3 rotationAxis = Vector3.Cross(basis2Effector, basis2Target); BoneManager.IKLimitter.Adjust(node.Name, ref rotationAxis); rotationAxis.Normalize(); if (!float.IsNaN(rotationAngle) && rotationAngle > 1.0e-3f && !rotationAxis.NaN) { // 関節回転量の補正 Quaternion subRot = Quaternion.CreateFromAxisAngle(rotationAxis, (decimal)rotationAngle); Quaternion.Multiply(ref subRot, ref node.LocalTransform.Rotation, out node.LocalTransform.Rotation); BoneManager.IKLimitter.Adjust(node); //関係ノードのグローバル座標更新 for (int i = nodeIndex; i >= 0; --i) {//順番に親子関係になっている。(Processorでチェックかけてある //GlobalTransformを仮更新 int parentBone = ik.IKChildBones[i].SkeletonHierarchy; ik.IKChildBones[i].LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[parentBone].GlobalTransform, out ik.IKChildBones[i].GlobalTransform); } effector.LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[effector.SkeletonHierarchy].GlobalTransform, out effector.GlobalTransform); } } } return(true);//UpdateGlobalをもう一度呼ぶ //IKチェインにぶら下がってるIK影響外のボーンを更新するため。 }
/// <summary> /// IKのソルブ /// </summary> /// <param name="ik">対象IK</param> /// <param name="BoneManager">ボーンマネージャ</param> /// <returns>呼び出し側でUpdateGlobalをもう一度呼ぶ場合はtrue</returns> public bool Solve(MMDIK ik, MMDBoneManager BoneManager) { #if SlimDX Vector4 localTargetPos = Vector4.Zero; Vector4 localEffectorPos = Vector4.Zero; #else Vector3 localTargetPos = Vector3.Zero; Vector3 localEffectorPos = Vector3.Zero; #endif //エフェクタとなるボーンを取得 MMDBone effector = ik.IKTargetBone; //IK対象のボーンのGlobalを更新(別のIK影響下のボーンからIKチェインが出ている場合があるので) Matrix local; for (int i = ik.IKChildBones.Count - 1; i >= 0; --i) {//順番に親子関係になっている。(Processorでチェックかけてある //GlobalTransformを仮更新 int parentBone = ik.IKChildBones[i].SkeletonHierarchy; ik.IKChildBones[i].LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[parentBone].GlobalTransform, out ik.IKChildBones[i].GlobalTransform); } effector.LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[effector.SkeletonHierarchy].GlobalTransform, out effector.GlobalTransform); //ターゲット位置の取得 Vector3 targetPos; MMDXMath.GetTranslation(ref ik.IKBone.GlobalTransform, out targetPos); //最大ループ回数分ループ for (int it = 0; it < ik.Iteration; ++it) { for (int nodeIndex = 0; nodeIndex < ik.IKChildBones.Count; ++nodeIndex) {//子ノードを子から順番に…… MMDBone node = ik.IKChildBones[nodeIndex]; //エフェクタの位置 Vector3 effectorPos; MMDXMath.GetTranslation(ref effector.GlobalTransform, out effectorPos); // 注目ノードの位置の取得 Vector3 jointPos; MMDXMath.GetTranslation(ref node.GlobalTransform, out jointPos); // ワールド座標系から注目ノードの局所座標系への変換 Matrix invCoord; Matrix.Invert(ref node.GlobalTransform, out invCoord); // 各ベクトルの座標変換を行い、検索中のボーンi基準の座標系にする // (1) 注目ノード→エフェクタ位置へのベクトル(a)(注目ノード) Vector3.Transform(ref effectorPos, ref invCoord, out localEffectorPos); // (2) 基準関節i→目標位置へのベクトル(b)(ボーンi基準座標系) Vector3.Transform(ref targetPos, ref invCoord, out localTargetPos); #if SlimDX //念のため…… // (1) 基準関節→エフェクタ位置への方向ベクトル Vector3 basis2Effector = Vector3.Normalize(new Vector3(localEffectorPos.X, localEffectorPos.Y, localEffectorPos.Z)); // (2) 基準関節→目標位置への方向ベクトル Vector3 basis2Target = Vector3.Normalize(new Vector3(localTargetPos.X, localTargetPos.Y, localTargetPos.Z)); #else // (1) 基準関節→エフェクタ位置への方向ベクトル Vector3 basis2Effector = Vector3.Normalize(localEffectorPos); // (2) 基準関節→目標位置への方向ベクトル Vector3 basis2Target = Vector3.Normalize(localTargetPos); #endif // 回転角 float rotationDotProduct = Vector3.Dot(basis2Effector, basis2Target); float rotationAngle = (float)Math.Acos(rotationDotProduct); //回転量制限をかける if (rotationAngle > MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1)) rotationAngle = MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1); if (rotationAngle < -MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1)) rotationAngle = -MathHelper.Pi * ik.ControlWeight * (nodeIndex + 1); // 回転軸 Vector3 rotationAxis = Vector3.Cross(basis2Effector, basis2Target); MMDCore.Instance.IKLimitter.Adjust(node.Name, ref rotationAxis); rotationAxis.Normalize(); if (!float.IsNaN(rotationAngle) && rotationAngle > 1.0e-3f && !MMDXMath.CheckNaN(rotationAxis)) { // 関節回転量の補正 Quaternion subRot = MMDXMath.CreateQuaternionFromAxisAngle(rotationAxis, rotationAngle); Quaternion.Multiply(ref subRot, ref node.LocalTransform.Rotation, out node.LocalTransform.Rotation); MMDCore.Instance.IKLimitter.Adjust(node); //関係ノードのグローバル座標更新 for (int i = nodeIndex; i >= 0; --i) {//順番に親子関係になっている。(Processorでチェックかけてある //GlobalTransformを仮更新 int parentBone = ik.IKChildBones[i].SkeletonHierarchy; ik.IKChildBones[i].LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[parentBone].GlobalTransform, out ik.IKChildBones[i].GlobalTransform); } effector.LocalTransform.CreateMatrix(out local); Matrix.Multiply(ref local, ref BoneManager[effector.SkeletonHierarchy].GlobalTransform, out effector.GlobalTransform); } } } return true;//UpdateGlobalをもう一度呼ぶ //IKチェインにぶら下がってるIK影響外のボーンを更新するため。 }