Ejemplo n.º 1
0
        /// <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影響外のボーンを更新するため。
        }
Ejemplo n.º 2
0
        public MMDModel Load(string filename, Dictionary<string, object> opaqueData)
        {
            //GraphicsDataのチェック
            if (!opaqueData.ContainsKey("GraphicsDevice"))
                throw new ArgumentException("opaqueデータに{\"GraphicsDevice\",GraphicsDevice}がありません", "opaqueData");
            GraphicsDevice graphics = opaqueData["GraphicsDevice"] as GraphicsDevice;
            if (graphics == null)
                throw new ArgumentException("opaqueデータに\"GraphicsDevice\"のキーはありましたが、ValueにGraphicsDeviceが入っていません");

            //PMDのロード
            MikuMikuDance.Model.MMDModel model = MikuMikuDance.Model.ModelManager.Read(filename);
            MikuMikuDance.Model.Ver1.MMDModel1 model1 = model as MikuMikuDance.Model.Ver1.MMDModel1;
            if (model1 == null)
                throw new System.IO.FileLoadException("ファイルのロードに失敗しました", filename);
            List<IMMDModelPart> parts = new List<IMMDModelPart>();
            MMDBoneManager manager;
            Dictionary<string, MMDMotionData> attachedMotion = new Dictionary<string, MMDMotionData>();
            long FaceIndex = 0;
            //ボーンマネージャの作成
            MMDBone[] bones = new MMDBone[model1.Bones.Length];
            for (int i = 0; i < bones.Length; ++i)
            {
                bones[i].BindPose
            }
            //マテリアルごとにモデルを作成
            for (long i = 0; i < model1.Materials.LongLength; ++i)
            {
                List<ushort> vertIndices = new List<ushort>();
                List<int> faceIndices = new List<int>();
                Dictionary<ushort, int> vertMap = new Dictionary<ushort, int>();
                //頂点インデックスの作成
                for (long j = FaceIndex; j < FaceIndex + model1.Materials[i].FaceVertCount; ++j)
                {
                    ushort VertIndex = model1.FaceVertexes[j];
                    int vpos;
                    if (vertMap.TryGetValue(VertIndex, out vpos))
                    {
                        faceIndices.Add(vpos);
                    }
                    else
                    {
                        vertMap.Add(VertIndex, vertIndices.Count);
                        faceIndices.Add(vertIndices.Count);
                        vertIndices.Add(VertIndex);
                    }
                }
                //インデックスバッファの作成(GraphicsDeviceがいる。どうする?)
                IndexBuffer indexbuffer;

                //頂点の作成
                MMDVertexNm[] verts;
                MMDVertexNmTx[] vertsTx = null;
                //頂点型判定と代入
                if (!string.IsNullOrEmpty(model1.Materials[i].TextureFileName))
                {
                    vertsTx = new MMDVertexNmTx[vertIndices.Count];
                    verts = vertsTx;
                }
                else
                    verts = new MMDVertexNm[vertIndices.Count];
                for (int vi = 0; vi < verts.LongLength; ++vi)
                {
                    MikuMikuDance.Model.Ver1.ModelVertex modelvert = model1.Vertexes[vertIndices[vi]];
                    verts[vi].Position = MMDXMath.ToVector3(modelvert.Pos);
                    verts[vi].Normal = MMDXMath.ToVector3(modelvert.NormalVector);
                    verts[vi].BlendWeights = new Microsoft.Xna.Framework.Vector2(modelvert.BoneWeight / 100f, 1.0f - modelvert.BoneWeight / 100f);
                    verts[vi].BlendIndexX = modelvert.BoneNum[0];
                    verts[vi].BlendIndexY = modelvert.BoneNum[1];
                    if (verts[vi].BlendIndexX < 0 && verts[vi].BlendIndexX >= manager.Count)
                    {
                        verts[vi].BlendWeights.X = 0;
                        verts[vi].BlendIndexX = 0;
                    }
                    if (verts[vi].BlendIndexY < 0 && verts[vi].BlendIndexY >= manager.Count)
                    {
                        verts[vi].BlendWeights.Y = 0;
                        verts[vi].BlendIndexY = 0;
                    }
                    if (vertsTx != null)
                        vertsTx[vi].TextureCoordinate = MMDXMath.ToVector2(modelvert.UV);
                }
                //不透明データを作成
                Dictionary<string, object> opaqueData = new Dictionary<string, object>();
                opaqueData.Add("IndexBuffer", indexbuffer);
                parts.Add(normalFactory.Create(faceIndices.Count / 3, verts, opaqueData));
            }
            return new MMDModel(parts, manager, attachedMotion);
        }