日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

【Ogre-windows】旋转矩阵及位置解析

發布時間:2023/12/13 windows 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Ogre-windows】旋转矩阵及位置解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

這篇博客主要針對三種問題

  • 如何創建動畫幀
  • 如何獲取全局位置
  • 如何計算全局旋轉矩陣

仿真環境為VS2013+Ogre1.10.9與matlab驗證

創建動畫幀

這里只做一個簡單的實驗: 將自帶的人物模型Jaiqua的run運動給新創建的運動myrun中并播放,直接貼代碼了

void JaiQua::createanim(){SkeletonInstance* skel = mEntity->getSkeleton();Animation *anim = skel->createAnimation("mywalk", 1.2667);anim->setInterpolationMode(Ogre::Animation::IM_SPLINE);Animation *orianim = skel->getAnimation("Walk");//原始運動Animation::NodeTrackIterator tracks = orianim->getNodeTrackIterator();while (tracks.hasMoreElements()){NodeAnimationTrack *track = tracks.getNext();//原始運動各關節遍歷Bone *bone = skel->getBone(track->getHandle());//獲取原始運動的各關節Bone *nbone = skel->getBone(bone->getName());//nbone->setManuallyControlled(true);Real framenum = track->getNumKeyFrames();//原始各關節總幀數NodeAnimationTrack *tracksnew = anim->createNodeTrack(nbone->getHandle(),nbone);//為新運動創建一個關節//依據原始運動各關節每幀數據對新運動各關節賦值cout << bone->getName() << ": ";for (Real i = 0; i < framenum; i++){Real currentframe = track->getKeyFrame(i)->getTime();//cout << "當前幀" <<currentframe << " "<<endl;TransformKeyFrame *newKf = tracksnew->createNodeKeyFrame(currentframe);//為當前關節創建一幀,輸入參數是時間點TransformKeyFrame *oriKf = track->getNodeKeyFrame(i);//獲取當前幀的原始運動關節,輸入參數是時間的索引//關節旋轉賦值Quaternion quat = oriKf->getRotation();Ogre::Matrix3 mat;quat.ToRotationMatrix(mat);newKf->setRotation(Quaternion(mat));}cout << endl;}mEntity->refreshAvailableAnimationState(); }

流程:

  • 這里需要注意的是Jaiqua的初始關節數是大于當前幀具有運動數據的關節數的,所以賦值的時候需要先看看初始的Walk運動中到底都給哪些關節賦值了, 方法就是代碼中的迭代器Animation::NodeTrackIterator tracks = orianim->getNodeTrackIterator(); 然后不斷循環即可, 獲取下一個關節的位置是迭代器的next函數.
  • 在循環體內部就可以依據每幀對每個關節的旋轉矩陣賦值, 關鍵一步是針對新運動mywalk創建關鍵幀, 函數是createNodeKeyFrame(),傳入參數是當前關鍵幀的時間點,比如0.3333,而非1、2之類的
  • 創建了關鍵幀, 就可以獲取一下原始運動Walk的當前關節當前幀getNodeKeyFrame(),注意傳入參數是時間點的索引如1、2,指示的是第幾幀, 而非0.333之類的
  • 最后就可以獲取此關節當前幀的選轉四元數getRotation, 隨后setRotation給新的運動的當前幀當前關節即可

播放動畫的時候直接獲取新運動即可

//創建RobotmEntity = mSceneMgr->createEntity("jaiqua.mesh");mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Ogre::Vector3(0, 0, 25.0));mNode->attachObject(mEntity);//創建動畫createanim();//動畫狀態mAnimationState = mEntity->getAnimationState("mywalk");mAnimationState->setEnabled(true);mAnimationState->setLoop(true);

骨骼旋轉矩陣、幀旋轉矩陣

旋轉一般都包含局部旋轉和全局旋轉, 需要注意的是與ASF/AMC動捕數據類似, 除了關節長度信息外, 骨骼自身每個還有旋轉信息, 這與BVH動畫數據不同, BVH骨骼只有offset骨骼長度信息, 這就導致了當前幀的局部旋轉并非由當前動畫幀中的rotation angle-axis直接得到, 還必須考慮骨骼自身的旋轉, 即當前幀當前關節局部旋轉是骨骼定義的旋轉與幀動畫定義的旋轉的乘積關系,具體是誰乘以誰,下面驗證

在渲染每一幀的時候,也就是函數frameRenderingQueued中, 我們加入如下語句獲取某個關節的骨骼內部旋轉(原始局部)、當前局部旋轉

Ogre::SkeletonInstance *skel = mEntity->getSkeleton();Ogre::Animation *anim = skel->getAnimation("mywalk");Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator();while (tracks.hasMoreElements()){NodeAnimationTrack *track = tracks.getNext();TransformKeyFrame *kf = track->getNodeKeyFrame(mAnimationState->getTimePosition()); //是索引,而非時間 Bone *bone = skel->getBone(track->getHandle());if (bone->getName() == "Spineroot"){cout << "時間: " << mAnimationState->getTimePosition() << " 關節: " << bone->getName() << endl;Ogre::Quaternion init_localrot = bone->getInitialOrientation();Ogre::Quaternion localrot = bone->getOrientation(); //bone->convertWorldToLocalOrientation(bone->getOrientation());Ogre::Matrix3 initlocalmat,localmat;localrot.ToRotationMatrix(localmat);init_localrot.ToRotationMatrix(initlocalmat);cout << "原始局部" << endl;showmatrix(initlocalmat);cout << "當前局部" << endl;showmatrix(localmat);cout << "----------------------------" << endl;}}

提取出Spineroot關節的第0時刻,即第一幀的旋轉信息

那么,這個數據怎么來的呢?用matlab仿真, 流程是就是讀取Jaiqua骨骼和運動幀的軸角對, 并用vrrotvec2mat()轉換成旋轉矩陣, 注意這個函數接受的是一個數組, 數組前三個元素分別為(x,y,z)角度, 第四個元素為角度制的角度(不要用deg2rad轉弧度制),但是轉換的結果通常與Ogre的轉換函數有點差異, 實驗一下


可以發現它倆剛好互為轉置, 所以在matlab中仿真的時候注意一下這一點,回過頭看我們的問題:原始局部和當前局部是如何通過Jaiqua.skeleton中的數據計算得到?

原始局部很簡單,其實就是bones中定義的初始骨骼旋轉

當前局部也即第1幀Spineroot旋轉是如何得到的?

最終的驗證結果是
當前關節局部旋轉矩陣=動畫幀定義旋轉×初始骨骼旋轉當前關節局部旋轉矩陣=動畫幀定義旋轉\times 初始骨骼旋轉 =×

vrrotvec2mat([-0.802018 0.597271 -0.00580183 0.25543])'*vrrotvec2mat([0.0283593 -0.998889 0.0376242 1.55034])'ans =0.1725 0.0026 0.98500.1380 0.9901 -0.0268-0.9753 0.1405 0.1704

#關節位置

全局位置關于這一個, 我目前還沒搞清楚每幀keyframe中translate參與計算的方式, 按理說這個數據是沒有任何作用的, 因為我們知道初始骨骼, 直接依據當前幀定義的旋轉矩陣就可以得到當前姿態, 無需額外的translate設置, 而且在matlab的仿真結果證明此數據并無用
【更新日志】并非無用, 這個對整個人體的位置還是有用的, 而除了指定人體位置的關節之外的關節, 這個translate是幾乎無用的, 而且可以發現它們的值都很小很小, 基本都乘以e?16e^{-16}e?16

在matlab中求解關節位置的關鍵代碼如下

tdof = squeeze(localRotM(ind,:,:)); xyzStruct(ind).xyz=skel.tree(ind).offset*xyzStruct(parent).rot+xyzStruct(parent).xyz; xyzStruct(ind).rot=tdof*skel.tree(ind).axisOrder*xyzStruct(parent).rot;

tdof代表的就是當前幀當前關節的局部旋轉, skel.tree(ind).offset代表初始骨骼定義的骨骼長度即position, skel.tree(ind).axisOrder代表的就是初始骨骼定義的旋轉, xyzStruct(parent).rot代表當前關節父關節的全局旋轉,最終計算的位置坐標如下:

Jaiqua0 0 0GlobalSRT1.0e-15 *-0.1110 0 0Spineroot2.1796 8.7556 -53.7141Spine012.1796 8.7556 -53.7141Spine022.2534 10.6250 -53.7025Spine032.3300 12.5657 -53.6904Lshoulderroot2.3426 14.3376 -53.6515Lshoulder2.3426 14.3376 -53.6515Larmroot0.7550 14.1863 -53.5923Lbicept0.7550 14.1863 -53.5923Lforearm-0.6631 11.6248 -53.2319Lhandroot-1.8638 9.4263 -53.9285Lhand-1.8638 9.4263 -53.9285Lfingers-2.5909 8.5843 -54.4267Rshoulderroot2.3382 14.3351 -53.6398Rshoulder2.3382 14.3351 -53.6398Rarmroot3.9311 14.3725 -53.7863Rbicept3.9311 14.3725 -53.7863Rforearm5.0354 11.6399 -53.6601Rhandroot4.6609 9.0743 -53.8534Rhand4.6609 9.0743 -53.8534Rfingers4.7810 7.8851 -54.0929neckroot2.3827 14.9406 -53.5743neck2.3827 14.9406 -53.5743head2.3325 15.4175 -53.7158Llegroot0.9231 8.9329 -53.5043Lthigh0.9231 8.9329 -53.5043Lshin1.1398 4.0498 -54.2153Lfooteffector1.5438 -0.4803 -53.4399Lfoot1.5438 -0.4803 -53.4399Ltoe1.2300 -1.0743 -54.5649Rlegroot3.3706 8.5802 -53.9321Rthigh3.3706 8.5802 -53.9321Rshin2.7365 3.8570 -55.2306Rfootroot3.2952 1.1392 -51.5247Rfoot3.2952 1.1392 -51.5247Rtoe3.0920 -0.0266 -52.0873

在Ogre中獲取當前關節相對于根關節的位置是bone->_getDerivedPosition()函數, 即在渲染函數中添加如下代碼

Ogre::SkeletonInstance *skel = mEntity->getSkeleton();Ogre::Animation *anim = skel->getAnimation("mywalk");Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator();while (tracks.hasMoreElements()){NodeAnimationTrack *track = tracks.getNext();TransformKeyFrame *kf = track->getNodeKeyFrame(mAnimationState->getTimePosition()); //是索引,而非時間 Bone *bone = skel->getBone(track->getHandle());if (mAnimationState->getTimePosition()==0){//bone->getName() == "Spineroot"cout << "時間: " << mAnimationState->getTimePosition() << " 關節: " << bone->getName() << endl;Ogre::Quaternion init_localrot = bone->getInitialOrientation();Ogre::Quaternion localrot = bone->getOrientation(); //bone->convertWorldToLocalOrientation(bone->getOrientation());Ogre::Matrix3 initlocalmat,localmat;localrot.ToRotationMatrix(localmat);init_localrot.ToRotationMatrix(initlocalmat);//cout << "原始局部" << endl;//showmatrix(initlocalmat);//cout << "當前局部" << endl;//showmatrix(localmat);cout << "初始位置" << endl;//cout << bone->getInitialPosition()<< endl;cout << bone->_getDerivedPosition() << endl;cout << "----------------------------" << endl;}

得到每個關節相對根關節的位置:

時間: 0 關節: head 初始位置 Vector3(2.33252, 15.4175, -53.7158) ---------------------------- 時間: 0 關節: neck 初始位置 Vector3(2.38266, 14.9406, -53.5743) ---------------------------- 時間: 0 關節: Rbicept 初始位置 Vector3(3.93105, 14.3725, -53.7863) ---------------------------- 時間: 0 關節: Rforearm 初始位置 Vector3(5.03536, 11.6399, -53.6601) ---------------------------- 時間: 0 關節: Rshoulder 初始位置 Vector3(2.33821, 14.3351, -53.6397) ---------------------------- 時間: 0 關節: Lshoulder 初始位置 Vector3(2.34262, 14.3376, -53.6515) ---------------------------- 時間: 0 關節: Lbicept 初始位置 Vector3(0.755036, 14.1863, -53.5923) ---------------------------- 時間: 0 關節: Lforearm 初始位置 Vector3(-0.663156, 11.6248, -53.2319) ---------------------------- 時間: 0 關節: Spine03 初始位置 Vector3(2.32999, 12.5657, -53.6904) ---------------------------- 時間: 0 關節: Spine02 初始位置 Vector3(2.2534, 10.625, -53.7024) ---------------------------- 時間: 0 關節: Spine01 初始位置 Vector3(2.17962, 8.75564, -53.7141) ---------------------------- 時間: 0 關節: Rthigh 初始位置 Vector3(3.37061, 8.58021, -53.932) ---------------------------- 時間: 0 關節: Rshin 初始位置 Vector3(2.73647, 3.857, -55.2306) ---------------------------- 時間: 0 關節: Lthigh 初始位置 Vector3(0.923067, 8.93287, -53.5043) ---------------------------- 時間: 0 關節: Lshin 初始位置 Vector3(1.13982, 4.04976, -54.2153) ---------------------------- 時間: 0 關節: Lfoot 初始位置 Vector3(1.5438, -0.48033, -53.4399) ---------------------------- 時間: 0 關節: Rfoot 初始位置 Vector3(3.29522, 1.13914, -51.5247) ---------------------------- 時間: 0 關節: Ltoe 初始位置 Vector3(1.22996, -1.07427, -54.5649) ---------------------------- 時間: 0 關節: Rtoe 初始位置 Vector3(3.09204, -0.0266533, -52.0873) ---------------------------- 時間: 0 關節: Spineroot 初始位置 Vector3(2.17962, 8.75564, -53.7141) ----------------------------

可以發現結果幾乎完全一樣,計算過程并未使用translate,只有在計算整個人體位置的時候涉及到, 上述代碼將人體位置設置為始終未(0,0,0)(0,0,0)(0,0,0)
#Translate作用
為了了解其作用, 這里在渲染代碼中書寫如下調試輸出

Ogre::SkeletonInstance *skel = mEntity->getSkeleton();Ogre::Animation *anim = skel->getAnimation("Sneak");Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator();while (tracks.hasMoreElements()){NodeAnimationTrack *track = tracks.getNext();TransformKeyFrame *kf = track->getNodeKeyFrame(mAnimationState->getTimePosition()); //是索引,而非時間 Bone *bone = skel->getBone(track->getHandle());if (bone->getName() == "Spineroot"){//mAnimationState->getTimePosition() == 0cout << "時間: " << mAnimationState->getTimePosition() << " 關節: " << bone->getName() << endl;Ogre::Quaternion init_localrot = bone->getInitialOrientation();Ogre::Quaternion localrot = bone->getOrientation(); //bone->convertWorldToLocalOrientation(bone->getOrientation());Ogre::Matrix3 initlocalmat,localmat;localrot.ToRotationMatrix(localmat);init_localrot.ToRotationMatrix(initlocalmat);/*cout << "原始局部" << endl;showmatrix(initlocalmat);cout << "當前局部" << endl;showmatrix(localmat);cout << "幀局部" << endl;showmatrix(initlocalmat.Inverse()*localmat);*/cout << "初始位置:" ;cout << bone->getInitialPosition()<< endl;cout << "當前位置:" ;cout << bone->_getDerivedPosition() << endl;cout << "位置差值";cout << bone->_getDerivedPosition() - bone->getInitialPosition() << endl;cout << "----------------------------" << endl;}}

然后對比第一幀輸出

這樣我們就得到結論
人體當前位置=初始骨骼定義位置position+動畫幀定義的關節translate人體當前位置=初始骨骼定義位置position+動畫幀定義的關節translate =position+translate

后記

本篇博客主要就是未后續的將任意的關節數據設置到OGRE中做準備, 重點就是要了解旋轉矩陣的到全局位置的計算方法。

以后想套入比如BVH或者ASF/AMC動捕數據的時候, 只需要保證初始骨骼姿態相同的情況下, 就可以將歐拉角轉換得到的旋轉矩陣應用到Ogre中,重點注意細節上的問題, 比如這個矩陣是否需要轉置或者翻轉后再運用之類的。

matlab仿真代碼:鏈接:https://pan.baidu.com/s/1kWUF3iZ 密碼:u792

Ogre仿真代碼:鏈接: https://pan.baidu.com/s/1uWEJ39pJcSvHvHSmTRD6_w 密碼: stmc

最后再貼一下可視化初始骨骼姿態結果(代碼都包含了)

Run運動第一幀的結果

總結

以上是生活随笔為你收集整理的【Ogre-windows】旋转矩阵及位置解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。