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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Ogre骨骼动画分析

發(fā)布時間:2024/3/13 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Ogre骨骼动画分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://3dlearn.googlecode.com/files/ogre skeleton animation.pdf

歡迎指出文中錯誤

1 ?前言

骨骼蒙皮動畫分兩步驟進(jìn)行:根據(jù)時間插值更新骨骼、然后根據(jù)骨骼更新每骨骼上的頂點。為了好玩,暫且這樣看:在每一個時間點,對每一個骨骼,我們創(chuàng)建一個骨骼魔法,并將骨骼魔法施放到每一個骨頭上;有個這些骨骼然后我們開始蒙皮,我們找出每一寸皮膚(一個頂點),并從骨堆里找出這塊皮需要依附的骨頭,當(dāng)然骨頭的數(shù)量都是有限的,一般就十幾或翻倍的數(shù)量級,所以骨頭還是比價好找的。我們將皮貼到骨頭上,貼完所有的皮,我們就得到了一個骨頭人鳥??雌饋砗苄蜗?/span>:
?

下頁示意圖少兒不宜.

?

?

?

?

2 ?類圖

?<只能看pdf>

?

3 ?邏輯切片

不解釋.

?

渲染

Root::renderOneFrame()

->Root::_updateAllRenderTargets

->RenderSystem::_updateAllRenderTargets()

->RenderWindow::update()

->D3D9RenderWindow::update(bool swap)

->RenderTarget::update()

->Viewport::update()

->Camera::_renderScene()

->SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)

?

4 ?更新骨骼

只考慮線性插值更新骨骼的情況.

4.1 ?創(chuàng)建一個骨骼魔法

創(chuàng)建一根骨頭需要的魔法。言歸正傳,其實就是創(chuàng)建一個TransformKeyFrame對象,看做一個全變換,一個變換只能應(yīng)用到一個骨骼上。當(dāng)前動作有24根骨頭,在每幀里,你需要對著24根骨頭施加24次骨骼魔法,如果美術(shù)認(rèn)為男人應(yīng)該是23根骨頭少畫了一根,可以不用糾結(jié),知道這不是bug就行。

一個骨骼文件看起來像這樣:

?

?

左邊定義的是骨頭,右邊定義的是動作。恩,這里只有18根骨頭,可以認(rèn)為這個不是人類骨骼數(shù)據(jù)。在程序?qū)崿F(xiàn)上,事實上考慮的術(shù)語叫joint,看起來像只是一個質(zhì)點,可以這樣理解,一個joint是一個空間射線,它表示了一個空間變化,也即一次旋轉(zhuǎn)縮放平移。當(dāng)然,它是一個矩陣,可以分解成一個平移和一個四元素變換。這時候似乎沒有骨骼的長度,可以認(rèn)為這個joint表示的只是骨頭的關(guān)節(jié)處,骨頭的長度隱藏在2個關(guān)節(jié)之間了。

右邊描述的是動作,一個動作是所有的joint在時間軸上的一個個切片組成的。恩,為了便于組織數(shù)據(jù),ogrejoint分類關(guān)鍵時間。其實也可以用關(guān)鍵時間來分類joint。恩,這其實也是一個很好的優(yōu)化方式,如果關(guān)鍵幀分類下省略了joint,就表示這個joint不需要變換,其對應(yīng)的頂點都不需要進(jìn)行重新蒙皮計算了。例如一個人在揮手,假設(shè)全身只有手在揮舞,當(dāng)然這動作應(yīng)看起來像個僵尸。按ogre現(xiàn)在的實現(xiàn),這個wave下的所有24(為了男女平等考慮男人和女人都是24根骨頭)joint都必須有關(guān)鍵時間,就算關(guān)鍵時間少幾處,也會將所有的joint進(jìn)行插值。這個時候避開某個joint被蒙皮,只有在這個動作下刪掉某個joint了。這徹頭徹尾就是個機(jī)器人鳥。如果用改進(jìn)的分類方式,在某個關(guān)鍵字里,可以省略一些joint,這樣一個人邊揮手邊輕邊擺頭還是可以實現(xiàn)的。

???????創(chuàng)建一個骨頭魔法分兩步,第一部是取到當(dāng)前時間點在關(guān)鍵幀中的插值系數(shù),第二部是根據(jù)這個插值系數(shù)對這個骨頭進(jìn)行插值。

t=(i-k1)/(k2-k1)

?

?

可以看到移動和縮放非常好理解,都是進(jìn)行的一次線性插值。只有旋轉(zhuǎn)使用了四元素的歸一化線性插值。兩個旋轉(zhuǎn)的插值似乎也只能用四元素插值,矩陣插值聽說有這樣那樣的問題。這個插值有誤差,并且不是恒速插值。

?

核心算法也是基本的線性插值公式,灰常神奇

q1+(q2-q1)*k

?

?

4.2 ?更新動畫時間

AnalyzeAnimation.exe!AnalyzeAnimation::frameRenderingQueued

OgreMain_d.dll!Ogre::Root::_fireFrameRenderingQueued

OgreMain_d.dll!Ogre::Root::_fireFrameRenderingQueued

OgreMain_d.dll!Ogre::Root::_updateAllRenderTargets

OgreMain_d.dll!Ogre::Root::renderOneFrame

OgreMain_d.dll!Ogre::Root::startRendering

AnalyzeAnimation.exe!BaseApplication::Go

AnalyzeAnimation.exe!WinMain

?

4.3 ?骨骼動畫的核心玩法(更新骨骼)

OgreMain_d.dll!Ogre::NodeAnimationTrack::applyToNode

OgreMain_d.dll!Ogre::Animation::apply

OgreMain_d.dll!Ogre::Skeleton::setAnimationState

OgreMain_d.dll!Ogre::Entity::cacheBoneMatrices

OgreMain_d.dll!Ogre::Entity::updateAnimation

OgreMain_d.dll!Ogre::Entity::_updateRenderQueue

OgreMain_d.dll!Ogre::RenderQueue::processVisibleObject

OgreMain_d.dll!Ogre::SceneNode::_findVisibleObjects

OgreMain_d.dll!Ogre::SceneNode::_findVisibleObjects

OgreMain_d.dll!Ogre::SceneManager::_findVisibleObjects

OgreMain_d.dll!Ogre::SceneManager::_renderScene

OgreMain_d.dll!Ogre::Camera::_renderScene

OgreMain_d.dll!Ogre::Viewport::update

OgreMain_d.dll!Ogre::RenderTarget::_updateViewport

RenderSystem_Direct3D9_d.dll

OgreMain_d.dll!Ogre::RenderTarget::_updateAutoUpdatedViewports

OgreMain_d.dll!Ogre::RenderTarget::updateImpl

OgreMain_d.dll!Ogre::RenderTarget::update

OgreMain_d.dll!Ogre::RenderSystem::_updateAllRenderTargets

OgreMain_d.dll!Ogre::Root::_updateAllRenderTargets????????????? --->先更新幀監(jiān)聽,再更新實體

OgreMain_d.dll!Ogre::Root::renderOneFrame

OgreMain_d.dll!Ogre::Root::startRendering

AnalyzeAnimation.exe!BaseApplication::go

AnalyzeAnimation.exe!WinMain

?

TransformKeyFrame?看做一個全變換.

?

對骨骼(bone/node)進(jìn)行變換的流程

輸入:節(jié)點、時間(省略權(quán)值和縮放)

輸出:節(jié)點的全變換

?

u?構(gòu)造出插值關(guān)鍵幀全變換buffer(TransformKeyFrame kf)

u?從關(guān)鍵幀buffer釋放一個平移buffer

u?對節(jié)點施加平移buffer (省略權(quán)值與縮放)

u?從關(guān)鍵幀buffer釋放一個旋轉(zhuǎn)buffer

u?對節(jié)點施加旋轉(zhuǎn)buffer

u?從關(guān)鍵幀buffer釋放一個縮放buffer

u?對節(jié)點施加一個縮放buffer

?

?

每幀對每一個骨骼(這里蛻化成node)4個關(guān)鍵幀buffer,正是骨骼動畫的核心玩法。

?

4.3.1 ?釋放一個關(guān)鍵幀魔法

關(guān)鍵幀魔法需要創(chuàng)建一個特殊的buffer,即關(guān)鍵幀全變換buffer(TransformKeyFrame).

?

?

?

5 ?蒙皮

Ogre蒙皮算法的核心是對每頂點進(jìn)行對應(yīng)骨骼的全變換。

?

V=M4*V

分兩步進(jìn)行,第一步在Mesh::softwareVertexBlend中準(zhǔn)備好計算數(shù)據(jù)結(jié)構(gòu)的上下文,第二步在softwareVertexSkinning中進(jìn)行每頂點的蒙皮計算。

?

?

處理軟件索引頂點混合,本意是用于骨骼動畫,但是也可用于其他用途.

?

?

?

const VertexData*

sourceVertexData

?

const VertexData*

targetVertexData

?

const Matrix4* const*

blendMatrices

?

size_t

numMatrices,

?

bool

blendNormals

?

?

sourceVertexData

頂點,法線,混合索引,混合權(quán)重

?

targetVertexData

目標(biāo)的頂點,混合版本的法線緩存.需要注意向量的歸一化.

?

blendMatrices

指向一個用于混合的矩陣數(shù)組,sourceVertexData的混合指數(shù)索引.

?

numMatrices

blendMatrices中矩陣數(shù)組的數(shù)量

?

blendNormals

true表示法線也同頂點一起混合.

?

?

?

?

srcElemPos

源頂點

?

srcElemNorm

源法線

?

srcElemBlendIndices

源混合索引

?

srcElemBlendWeights

源混合權(quán)重

?

?

?

?

?

?

?

srcPosBuf??????

源頂點緩存

?

srcIdxBuf??????

源索引緩存

?

srcWeightBuf?

源權(quán)重緩存

?

srcNormBuf

源法線緩存

?

destElemPos

目頂點

?

destElemNorm

目法線

?

??????

?

?

destPosStride

目法線跨步

?

?

?

?

?

?

?

?

5.2 ?蒙皮核心算法

核心算法如下

?

?

首先對頂點進(jìn)行計算

ü?找到當(dāng)前的混合索引值

ü?用這個值索引出混合矩陣M4

ü?M4左乘以頂點V1(*)得到V2

ü?V2進(jìn)行加權(quán)計算得到V3(=V2*weight)

ü?V3歸一處理得到V4(=V3.normalized)

?

然后對法線進(jìn)行同樣過程的計算,只是上面流程中的(*)?處的V1換成法線.如果一個頂點存在多個權(quán)重值,需要對每一個權(quán)值重復(fù)上面的14步驟進(jìn)行累積計算到V3.一次頂點計算完成,即對下一個頂點進(jìn)行同樣的計算過程.所有頂點計算完成,即完成了骨骼蒙皮.

總結(jié)

以上是生活随笔為你收集整理的Ogre骨骼动画分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。