2D動畫spine渲染原理解析與源碼解讀

前言:什麼是spine?

爲了讓初學者有更加直觀的初步的瞭解,筆者提供了一個簡單的示意圖以下:
image.png
實際開發中,由設計人員提供對應的spine編輯器所導出的動畫素材,開發人員選用對應的spine運行庫對素材進行消費和上屏渲渲染,即是spine所作的事,相比gif、css幀動畫、apng具有更增強大的靈活性。css

簡單比較以下:web

類型\項 顏色 大小 兼容性 靈活性 成本
GIF 256色
CSS幀動畫 真彩 較大 通常
APNG 真彩 部分瀏覽器兼容
spine2D動畫 真彩 大(動畫素材+運行庫引入) 較優

GIF因爲其自己的色彩限制,通常不能知足設計的要求,所以目前大多采用CSS幀動畫和APNG的方式處理頁面動畫,小區域動畫採用apng,大區域動畫能夠考慮採用CSS幀動畫或JS動畫處理。而釐米秀這裏因爲業務自己複雜且形象裝扮多變,故不得不採用spine2D動畫的方案。json

註釋:canvas

1)、JSON文件/二進制文件:存儲骨架信息,見下文介紹。瀏覽器

2)、素材圖片:相似雪碧圖,也可單一素材,可導出一張或多張。架構

3)、與素材圖片對應的atlas文件:記錄素材圖片在雪碧圖上的位置信息特徵等。一個atlas文件可對應多個素材圖片。app

1、基本概念

一、骨架Skeleton:指代的是數據的集合,包含構成此骨架的全部骨骼、插槽、附件及其餘信息。編輯器

二、骨骼bones:以官方示意圖爲例,一我的物自己由多個關節的骨骼組成。除了根骨骼之外,每一個骨骼都有對應的父骨骼,骨骼與骨骼之間的關係最終構形成相似樹的結構。函數

image.png

三、插槽slot:一個骨骼bone下可能有多個slot插槽,每一個slot插槽下能夠放置一個附件實例。插槽自己的存在有兩個重要的意義,一個是靈活的控制渲染順序,一個是分組同類附件。一個插槽能夠有多個附件,但一次只能看到一個。舉個簡單的栗子,圖中手槍所在的位置的插槽是"武器"插槽,而該插槽能夠放置不一樣的武器附件,例如"手槍"附件或"菜刀"附件。動畫

四、附件attachment:slot插槽內當前渲染的附件實例,即真實上屏渲染的實物素材。(可能須要對素材作旋轉、偏移、縮放甚至網格化mesh處理)。

五、皮膚skin:skin能夠看作是attachment的集合,或者能夠認爲是attachment的一個映射查詢表,一我的物能夠由多套skin,經過切換skin的方式去查詢不一樣的附件映射表,即可以變相的實現人物的全身換裝。

其餘相關概念:

關鍵幀:

在編輯器中,動畫是藉助關鍵幀完成的,從開始到結束的過渡動畫,由spine補間處理。

權重與網格:

權重用於將網格頂點綁定到一個或多個骨骼。變換骨骼時,頂點也會隨之變換。權重令網格可以隨着操縱骨骼而自動變形,從而讓本來複雜的網格變形動畫變得與骨骼動畫同樣簡單。

附件類型:
一、區域附件:普通的圖片展現附件。
二、點附件:空間中的一個點和旋轉,相比骨頭的優點能夠爲不一樣的皮膚設置更改位置和旋轉,例如不一樣的槍從不一樣的位置射擊。
三、網格附件:支持在圖片內設置多邊形,以後可操縱多邊形的頂點,以有效的方式讓圖片彎曲和變形。
四、邊界框附件:附加到骨骼上的多邊形,骨骼變化的時候也會隨之變形,可用於撞擊檢測,建立物理主體等。
五、剪裁附件:剪裁功能讓你能夠定義一個多邊形區域,與邊界框附件相似,它會屏蔽繪製順序中的其餘插槽。
六、路徑附件:用於設置路徑。

其中在業務中比較經常使用到的是區域附件和網格附件。

三種約束:
一、IK約束:反向動力學約束 子骨頭終點固定的場景。
二、變換約束:變換約束指的是將對骨骼的世界旋轉、移動縮放等複製到多個骨骼上。
三、路徑約束:使用路徑來調整骨骼變換,骨骼能夠沿着路徑,也能夠調整旋轉以指向路徑。

2、spine架構和核心類解讀

spine總體架構分層以下:

image.png

spine核心類以下:
image.png

讀懂上面這張官方所提供的類圖,將會對spine的總體架構設計有更加明確的瞭解和認識。

一、Loading模塊:是針對資源加載的處理,一個spine形象的骨架信息導出後,通常會導出爲json或者二進制文件的形式,因爲json形式純文本文件過大,因此官方提供了二進制文件導出的形式,而且輔以運行庫的代碼針對二進制文件進行解析。其次,Loading模塊中的atlasAttachmentLoader將會負責atlas文件的解析,因爲atlas文件自己是字符串的形式,內部包含雪碧圖中素材的位置信息,因此須要解析後與素材創建」關聯關係「。例如:Eyes-close素材在picture1.png圖片中的x,y位置 旋轉角度爲z,而構造出來的這種映射關係將用於被實例化attachment的時候消費。

二、Spine Texture Atlas模塊:一張素材圖映射一個atlasPage,一張素材圖中的某個區域塊映射一個atlasRegion,而region的詳細繪製信息本質上已經在上個模塊完成。

三、Rending模塊:由渲染層遍歷slot進行渲染,這裏不作詳解,渲染層並不是spine核心庫所負責的部分,上屏渲染能夠由canvas、webGL或者其餘第三方渲染庫渲染,例如pixijs。

四、SetupPoseData模塊:或者稱之爲SkeletonData模塊,數據源從這裏輸入進行處理,可是並非最終數據,能夠理解爲這裏對數據作了一層預處理,會將骨骼數據先處理爲boneData,插槽數據處理爲slotData,固然也有部分數據不須要被再次處理,在這裏,也會根據前面生成的atlasRegion去構造出對應的附件實例,存儲進skin中,skin本質上爲附件映射表。

其次,數據對象自己和實例對象是有差異的。

數據對象是無狀態的,可在任意數量的骨架實例間共用。有對應實例數據的數據對象類名稱以「Data」結尾,沒有對應實例數據的數據對象則沒有後綴,如附件、皮膚及動畫。

實例對象有許多屬性與數據對象相同。數據對象中的屬性表明裝配姿式,一般不會改動。實例對象中的相同屬性表示播放動畫時該實例的當前姿式。每一個實例對象保有一個其數據對象參考,用於將實例對象重置回裝配姿式。

例如,SkeletonData是數據對象,而Skeleton是實例對象。

五、Instance Data模塊:或者稱之爲Skeleton模塊,Skeleton實例自己是渲染層上屏渲染的真實直接數據源,渲染層將讀取Skeleton實例上的插槽信息,渲染對應的附件,在這裏,許多數據對象已經被處理成對應的實例對象,例如boneData已經被處理爲Bone實例,slotData已經被處理爲Slot實例;其次,如圖中所展現的,Skeleton實例中有兩個比較關鍵的方法,updateWorldTransform和setToSetUpPose。

updateWorldTransform爲更新世界變換,本質是觸發骨骼位置的計算,因爲骨骼位置可能發生旋轉偏移,其對應的子骨骼也會受到影響,所以須要更新世界變換從新計算全部骨骼的最新座標位置。

setToSetUpPose爲更新實例到當前初始狀態,通常才初始化時或重置人物狀態時調用,會將人物形象骨骼裝扮等切換爲初始最初的狀態。

六、Animation模塊:動畫模塊被單獨抽離,不只更方便維護和更新實例的狀態信息,總體架構邏輯也簡潔明瞭,由動畫state實例去觸發skeleton實例的更新,接下來skeleton實例調用updateWorldTransform更新世界變化,以後從新上屏渲染。

一個動畫實例中由多個timeline構成,這些timeline實例來自於不一樣的變種Timeline類,根本上都繼承與底層的TimeLine類,因爲一個動畫過程當中可能涉及多種變化,所以須要對不一樣的動畫進行劃分區別,處理旋轉的單獨一條timeline,處理縮放的單獨一條timeline,等等。而雖然不一樣類別動畫會抽離成不一樣的timeline,可是最終某個時間節點生效觸發,全部的timeline"做用"都是同時的。

3、spine源碼解讀

一、Slot:存儲插槽的當前姿式。插槽爲{@link Skeleton#drawOrder}目的組織附件,並提供存儲附件狀態的位置。狀態不能存儲在附件自己中,由於附件是無狀態的,能夠跨多個骨架共享。
(deform屬性是針對mesh附件的處理信息。)
(經過setToSetUpPose設置初始動做)
(在slot實例裏能夠直接getAttachment和setAttachment)

二、SlotData:slot實例裏用的數據的數據格式,包含index、插槽名稱、附件名稱、boneData等。

三、BoneData:骨頭實例裏用的數據格式,包含index(骨頭也有index)、骨頭名稱、父骨頭數據、骨頭本地轉換數據、世界轉換的模式。

四、Bone:關鍵方法updateWorldTransformWith,更新骨骼的世界座標。包含其餘的一些方法,世界座標和本地座標的轉換,旋轉轉換等。

五、SkeletonData: Skeleton實例對應的數據格式。包含bones、slots、skins、events、animations、各類約束。提供了
因爲是數據對象,僅提供了一些findbone、findslot的方法。

六、Skeleton:根據data新建Bone和Slot。bone有index按順序創建關聯關係。調用setToSetupPose將bone和slot設置到初始位置。會遍歷調用bone和slot對應的方法。updateWorldTransform調用bone的updateWorldTransform更新骨骼位置。提供了一些Bone、slot、attachment的get、set方法。
有個update方法,更新time時間。

七、SkeletonBinary:用於讀取二進制的skeleton文件。

八、SkeletonBounds:收集每一個可見的BoundingBoxAttachment,並計算其多邊形的世界頂點。主要用於碰撞或者命中檢測。由渲染層調用。

九、SkeletonCilpping:主要針對ClippingAttachment的處理,由渲染層調用。

十、SkeletonJson:用於解析處理spine導出的skeleton json。須要對應傳入一個attachmentLoader讓其能構造對應的attachment實例,處理bone、slots、ik、skins、animation等數據。
處理bone和slot構造對應的實例data。
處理skins藉助loader生成對應附件實例。
處理 animations生成不一樣的timeline實例對象。
最終構造出對應的SkeletonData實例。

十一、Skin:一套皮膚下的全部attachment都在skin實例下,提供了操做skin和attachment的方法。這裏操做的方法至關於dictionary,不是改變人物裝扮的。

十二、attachment目錄:各類附件的處理處理方法,繼承於Attachment基類。實際由對應的AttachmentLoader調用對應的附件類方法。
AtlasAttachmentLoader實現了對應方法。

1三、Texture:定義了Texture抽象類,定義一些抽象方法須要被實現。

1四、TextureAtlas:針對atlas文本進行解析處理,實現TextureAtlasReader進行逐行讀取,texture
藉助外部傳入的textureLoader回調來獲取對應的紋理。
每塊小素材對應一個TextureAtlasPage,素材信息讀取解析後構造對應TextureAtlasRegion。

1五、AnimationStateData:存儲AnimationState動畫更改時要應用的混合(交叉淡入淡出)持續時間。

1六、AnimationState:隨着時間調用動畫,動畫入隊等待播放,容許多個動畫疊加。
分多個track存儲動畫、區分不一樣動畫的timeline,針對event事件的處理邏輯等。

1七、Animation:實現了各類timeline類,Animation負責調用apply方法觸發更新,其apply方法會調用各個timeline的apply方法更新。timeline類中實現找到對應關鍵幀 決定如何渲染。

1八、AssetManager:靜態資源管理,包括拉取文本資源、拉取二進制資源、加載紋理。調用TextureAtlas處理atlas文本等。

4、渲染庫代碼解讀

canvas:
一、AssetManager:沒有作啥,直接沿用core裏的AssetManager
二、canvasTexture:繼承Texture。
三、SkeletonRender:傳入skeleton數據,渲染畫布,
drawImage會遍歷drawOrder中的slot,逐個渲染region附件,藉助ctx.drawImage API來裁剪和渲染圖片。
drawTriangles會計算頂點,渲染調試模式的綠色線條。

threejs:
一、ThreeJsTexture:針對threesjs自己的texture作了一層包裹,處理了一下filter。
二、MeshBatcher:MeshBatcher繼承自Threejs自己的Mesh。調用SkeletonMeshMaterial獲取材質。
三、SkeletonMesh:SkeletonMeshMaterial繼承自ShaderMaterial,這裏包含了着色器代碼,頂點着色器和片元着色器。
SkeletonMesh繼承自Object3D類。
核心渲染函數updateGeometry,skeleton更新世界變化後,調用渲染函數,遍歷drawOrder。
RegionAttachment和MeshAttachment會進行渲染,渲染藉助MeshBatcher,紋理做爲素材傳入batchMaterial。

webgl:
一、GLTexture:獲取畫布,渲染對應的image到畫布上。
二、Camera:設置相機位置
三、WebGL:定義了ManagedWebGLRenderingContext,其實就是獲取webgl的context上下文。
四、Input:對元素作事件監聽,鼠標、touch事件。
五、Shader:自行實現的着色器,片元和頂點。
六、SkeletonRenderer:負責skeleton的上屏渲染,渲染函數須要藉助PolygonBatcher來上屏渲染,一樣的,只會對RegionAttachment和MeshAttachment會進行渲染。
七、PolygonBatcher:在這裏綁定着色器,設置混合模式,綁定一個Mesh實例對象,Mesh爲單獨封裝的mesh類,最終調用的是Mesh暴露的渲染方法。
八、Mesh:單獨封裝的Mesh類,容許設置指數和頂點,上屏渲染藉助context的drawElements和drawArrays方法。
九、SceneRenderer:最上層的調用類,實例化batcher、webgl上下文、shader,實例化SkeletonRenderer,暴露不一樣的渲染方法,包括drawSkeleton,drawSkeletonDebug、drawTexture、drawRegion等。

5、spine渲染總體流程圖

根據前面的介紹,咱們對基本概念有所瞭解,而且瞭解了spine的總體架構設計,針對核心模塊進行了介紹,同時對spine核心庫源碼以及渲染層源碼的關鍵邏輯進行解讀,能夠整理出spine渲染的總體流程圖以下:
image.png

看到這裏相信你對spine的總體架構設計,渲染流程都已經有了大體的瞭解,接下來在明確了底層內部的處理流程後,咱們的下一步工做是實現換裝和換動做API,具體如何實現,請聽下回分解!

謝謝觀看~~

相關文章
相關標籤/搜索