Text Input

Text Input Animation

インクレディブル婦人の腕の動きを Text File から入力します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. 上腕と下腕と手首の姿勢を Text File から入力してアニメーションします。
    アニメーションの動きを定義した Text File(anime.txt) です。
    プロジェクトのフォルダーに格納して加えて下さい。
    モーションデータは Anime Table のモデルポーズテーブルと同じです。
    先頭の3はアニメーションを構成するパーツの数です。
    3,
    { (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0) }, 
    { (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), (0.0, 0.0, 0.5) }, 
    { (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0) }, 
    { (0.0, 0.0, 0.0), (0.0, 0.0, -1.0), (0.0, 0.0, -0.3) }, 
    { (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0) } };
    
  2. CreateDeviceDependentResources() の先頭で anime.txt を入力します。
    入力したテキストデータをパラメータとして SetPose(str); を呼び出します。
    void Sample3DSceneRenderer::CreateDeviceDependentResources()
    {
        StorageFolder^ folder =
            Windows::ApplicationModel::Package::Current->InstalledLocation;
        create_task(folder->GetFileAsync(L"anime.txt")).then([this](StorageFile^ file)
        {
            return FileIO::ReadTextAsync(file);
        }).then([this](task<String^> previousTask)
        {
            try
            {
                String^ str = previousTask.get();
                SetPose(str);   // Set Pose Vector
            }
            catch (...)
            {
                OutputDebugString(L"test.txt: <not found>");
            }
        });
    
        // シェーダーを非同期で読み込みます。
            ・・・
    
  3. Sample3DSceneRenderer.h にアニメーション用の領域を定義します。
    vector<float3> m_Pose; が anime.txt のデータを float3 に変換して格納する領域です。
    m_txt には SetPose(str) で渡された String^ を wstring に変換して格納します。
            void SetPose(String^ str);
            bool Token();
            std::wstring    m_txt;
            std::wstring    DWord;
            unsigned        m_pos;
            vector<float3>  m_Pose;     //アニメーションデータ
            int     m_parts;    //パーツ数
            int     m_scene;    //シーン数
            int     t_cnt;      //描画中のシーン
    
  4. anime.txt を解析して vector<float3> に格納する SetPose(String^ str) 関数です。
    ストアアプリの String^ は使い難いので wstring に変換して解析します。
    bool Token() 関数で m_txt[m_pos] からトークンを切り出します。
    先頭のパーツ数(3,)を切り出して m_parts に格納します。
    パーツの数が変わっても柔軟に対応するためです。
    後は Text の最後まで float データを切り出して m_Pose にスタックします。
    スタックされた件数からシーンの数(m_scene) を計算します。
    // str を解析してアニメーションデータを格納 
    void Sample3DSceneRenderer::SetPose(String^ str)
    {
        float3  fw;
        m_txt = str->Data();
        m_pos = 0;
        m_Pose.clear();
        if (!Token())   return;
        m_parts = _wtoi(DWord.data());
        while(m_pos<m_txt.length())
        {
            if (!Token())   break;
            fw.x = (float)_wtof(DWord.data());
            if (!Token())   break;
            fw.y = (float)_wtof(DWord.data());
            if (!Token())   break;
            fw.z = (float)_wtof(DWord.data());
            m_Pose.push_back(fw);
        }
        m_scene = (m_Pose.size() / m_parts) - 1;
    }
    
  5. トークンを切り出す bool Token() 関数です。
    false がリターンされるとデータの終わりです。
    // m_txt[m_pos] から次の Token を取得 ⇒ DWord に設定
    bool Sample3DSceneRenderer::Token()
    {   unsigned    wk;
        if (m_pos>=m_txt.length())  return false;
        m_pos = m_txt.find_first_not_of(L" ,;(){}\r\n", m_pos);
        wk = m_txt.find_first_of(L" ,;)}\r\n", m_pos);
        if (wk<=m_pos)  return false;
        DWord = DWord.assign(m_txt, m_pos, wk-m_pos);
        m_pos = wk+1;
        return true;
    }
    
  6. Rotate() 関数からモデル1とモデル2とモデル3の Update() 関数を呼び出します。
    戻り値が true(t_cnt==0)のとき SetRot() 関数でポーズを切り替えます。
    void Sample3DSceneRenderer::Rotate(float radians)
    {
        if (camera[0]->Update())
        {   SetRot();  }
        else
        {   camera[1]->Update();
            camera[2]->Update();
        }
    }
    
  7. ポーズを切り替える SetRot() 関数です。
    t_cnt と t_cnt+1 番目の m_Pose を参照して m_rot と m_dtrot を設定します。
    ポーズ間の動きを100分割して m_dtrot に格納します。
    これで先のプログラムと同様にアニメーションされます。
    void Sample3DSceneRenderer::SetRot()
    {
        int     i, pt;
        pt = t_cnt * m_parts;
        for(i=0; i<3; i++)
        {
            camera[i]->m_num = 100;
            camera[i]->m_rot = m_Pose[pt+i];
            camera[i]->m_dtrot.x = (m_Pose[pt+m_parts+i].x-m_Pose[pt+i].x)/100.0f;
            camera[i]->m_dtrot.y = (m_Pose[pt+m_parts+i].y-m_Pose[pt+i].y)/100.0f;
            camera[i]->m_dtrot.z = (m_Pose[pt+m_parts+i].z-m_Pose[pt+i].z)/100.0f;
        }
    
        t_cnt++;
        if (t_cnt>=m_scene) t_cnt = 0;
    }
    

カメラ座標と相対位置

  1. カメラ座標とパーツの相対位置は組み合わせるモデル(X-FILE)によって変わります。
    そこで汎用性を考慮して、これらの情報も Text File から入力してみましょう。
    先頭の3はアニメーションを構成するパーツの数です。
    次の3行がカメラの座標(m_eye)で、次の3行が親からの相対位置(m_pivot)です。
    3,
    {0.0f, 0.7f, 20.0f}
    {0.0f, 0.7f, 20.0f}
    {0.0f, 0.7f, 20.0f}
    {0.0f, 0.0f, 0.0f}
    {-4.0f, 0.0f, -0.6f}
    {-5.0f, 0.0f, 0.0f}
    
    (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0),
    (0.0, 2.0, 0.0), (0.0, 0.0, 1.0), (1.5, 0.0, 0.0),
    (0.0, 0.0, 0.0), (0.0, 0.0, 0.0),(-0.3, 0.0, 0.0),
    (0.0, -2.0, 0.0), (0.0, 0.0, -1.0), (-2.0, 0.0, 0.0),
    (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0),
    
  2. SetPose() 関数は次のようになります。
    Camera() 関数と m_pivot はここで設定します。
    void Sample3DSceneRenderer::SetPose(String^ str)
    {
        vector<float3>  vf3;
        float3  fw;
        m_txt = str->Data();
        m_pos = 0;
        m_Pose.clear();
        if (!Token())   return;
        m_parts = _wtoi(DWord.data());
    
        for(int i=0; i<m_parts*2; i++)
        {   if (!Token())   return;
            fw.x = (float)_wtof(DWord.data());
            if (!Token())   return;
            fw.y = (float)_wtof(DWord.data());
            if (!Token())   return;
            fw.z = (float)_wtof(DWord.data());
            vf3.push_back(fw);
        }
        camera[0]->Camera(vf3[0].x, vf3[0].y, vf3[0].z);
        camera[1]->Camera(vf3[1].x, vf3[1].y, vf3[1].z);
        camera[2]->Camera(vf3[2].x, vf3[2].y, vf3[2].z);
        camera[0]->m_pivot = vf3[3];
        camera[1]->m_pivot = vf3[4];
        camera[2]->m_pivot = vf3[5];
    
        while(m_pos<m_txt.length())
        {
            if (!Token())   break;
            fw.x = (float)_wtof(DWord.data());
            if (!Token())   break;
            fw.y = (float)_wtof(DWord.data());
            if (!Token())   break;
            fw.z = (float)_wtof(DWord.data());
            m_Pose.push_back(fw);
        }
        m_scene = (m_Pose.size() / m_parts) - 1;
    }
    
  3. モデル(X-FILE)の名前は Sample3DRender.cpp で指定しているので、汎用的とは言えないかもしれませんが、参考にして下さい。
    Text File(anime.txt) では、上腕と下腕と手首を少し大きく動かしてみました。

[Previous Chapter ↑] Table Animation

超初心者のプログラム入門(DirectX Store)