1. 程式人生 > >菜鳥也能學cocos2dx 3.0 骨骼動畫spine

菜鳥也能學cocos2dx 3.0 骨骼動畫spine

首先我們來看到底什麼是骨骼動畫:

在早期的機器上,渲染本身已經佔用了很多CPU資源,因此,對於渲染,往往採取的是一種空間換時間的策略,以避免在模型的渲染中繼續加重CPU的負擔。
幀動畫模型在這種條件下應運而生。比較著名的幀動畫格式是Quake2所採用的MD2。
到今天為止,幀動畫依然存在,只不過幀動畫更多地是來描述小且動作相對少些的物體。

GPU出現後,CPU的問題早已不像以前那麼突出,一些新的手段和技術也可以被應用進來了。
骨骼動畫相對於幀動畫而言,更加靈活多變,但同時,骨骼動畫需要更多的計算量,因此骨骼動畫往往應用在需要著重體現動作細節的模型中。

骨骼動畫技術後於幀動畫技術出現。
最開始,骨骼動畫僅用於非實時渲染的建模領域,如3DMax這類建模軟體之中,以方便美工的建模。
後來,CPU從渲染中解放後,骨骼動畫才用於實時渲染的遊戲中。

骨骼動畫原理

骨骼動畫的想法來源於人體骨骼。
例如說,人的上肢所有肌肉和面板都受上肢骨胳的影響,而人的踝關節則分別承受小腿骨胳和腳骨的影響。
根據這個我們可以將骨骼動畫理解為兩個概念: 骨骼:用以控制蒙皮的一種抽象的概念,如人體骨骼控制面板。 蒙皮:被骨骼控制、並顯示在外的因素,如人體的面板被骨骼所影響。

骨骼動畫原理:蒙皮(SKINMESH)

在最終的渲染結果中,蒙皮將完全顯示出來,蒙皮實際上就是頂點、法線和紋理座標等將被渲染的元素。
而其中,最關鍵的當然是頂點,頂點將直接被骨頭牽扯運動,因而使得整個模型呈現骨骼所決定的樣子。

骨骼動畫原理:骨骼(SKELETON)

骨骼是一種抽象的概念,在最終的渲染結果中,它不可見。
類如人體骨骼、骨骼是若干骨頭(Bone)成樹狀的集合體,而每塊骨頭又分別與若干數量的蒙皮頂點關聯。
當骨頭運動的時候,與之關聯的所有蒙皮頂點也會受骨骼的影響而運動。

骨頭與蒙皮頂點的關聯需要考慮到每塊骨頭對蒙皮頂點的影響。 儘管大部分情況下,一個頂點將僅僅被一個骨頭的影響,但是關節處的頂點往往被多根骨頭影響,例如踝關節,可能會分別受小腿骨50%和腳骨50%的影響,這種影響叫作權重(Weight)。
在這種情況下,我們稱踝關節的這些頂點,受小腿骨影響的權重是50%,受腳骨影響的權重也是50%。

而在cocos2dx中常用的骨骼動畫編輯器就是cocosStudio和spine了。

但是就我的感受,2款編輯器中spine可以說是完爆ccs的骨骼動畫部分,不僅因為spine容易上手,並且它提供了mesh,通常來說一張紋理只有4個頂點,左下右下左上右上,但是有了mesh,我們可以抓取這個圖片,並設定大量的頂點給它,之後就能通過對頂點的設定完成圖片的拉伸形變,比如乳搖功能。

spine中30幀為1s,最新版中也提供了IK,可以將骨骼固定,做動作。

具體的編輯我就不說了,主要說一下執行庫。

首先提供spine的最新執行庫,當然這不是官方的,裡面封裝了ffd,是我自己修改過並添加了ffd程式碼,採用newSkeletonAnimation區別原先的skeletonAnimation具體點選:spine FFD runtime  

其中要注意的幾個地方:

1.  1.8版本以上的atlas做了修改 在第二行添加了size 所以只要刪除size這一行即可,


2. 動作製作的時候如果層級有發生改變或者切換了skin,slot,請K幀一下,修改的部分:draworder和bone,一般首尾都K一下就行了。

3.至於.skel的binary檔案,是spine本身就提供的二進位制檔案,效能必然高於json,本人目前正在修改完善spine runtime的binary(因為官方也不提供,完成起來慢了點,以後或許會放出)。

4.newskeletonanimation在create時候最後一個引數scale別忘了。

說一下runtime中常用的一些方法:

skeletonNode = NEWSkeletonAnimation::createWithFile("spineboy.json", "spineboy.atlas", 0.6f);//建立動作,最後的引數為scale.

        skeletonNode->startListener = [this] (int trackIndex) {//設定動作開始檢測的監聽器
	spTrackEntry* entry = spAnimationState_getCurrent(skeletonNode->state, trackIndex);//獲得當前動作的狀態資訊
	const char* animationName = (entry && entry->animation) ? entry->animation->name : 0;
		log("%d start: %s", trackIndex, animationName);
	};
	skeletonNode->endListener = [] (int trackIndex) {//同理,結束動作監聽
		log("%d end", trackIndex);
	};
	skeletonNode->completeListener = [] (int trackIndex, int loopCount) {//同理,完成動作監聽
		log("%d complete: %d", trackIndex, loopCount);
	};
	skeletonNode->eventListener = [] (int trackIndex, spEvent* event) {//同理,事件監聽,在spine中編輯好event匯出
		log("%d event: %s, %d, %f, %s", trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue);
	};

	skeletonNode->setMix("walk", "jump", 0.2f);//協調動作
	skeletonNode->setMix("jump", "run", 0.2f);
	skeletonNode->setAnimation(0, "walk", true);//設定動作,可用多個set進行動作混合
	spTrackEntry* jumpEntry = skeletonNode->addAnimation(0, "jump", false, 3);//新增動作,在上個動作直接玩之後,之後為迴圈引數和delay
	skeletonNode->addAnimation(0, "run", true);

	skeletonNode->setStartListener(jumpEntry, [] (int trackIndex) {
		log("jumped!");
	});</span>

 skeletonNode->timeScale = 0.3f;//動作間隔
 skeletonNode->debugBones = true;//debug模式
 skeletonNode->update(0);//更新動作
 spBone* root=skeletonNode->findBone("root");//找到name為root的骨骼,同理  通過 findslot 可以找到名字為name的slot

順便吐糟一下cocos2dx 官方,雖說cocosstduio是親兒子吧,但是也不能不管spine啊,spine的ffd一直愣是沒加上去,逼得我自己改過來- =!