<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 6610字,需瀏覽 14分鐘

           ·

          2021-05-30 11:55

          作者:曾培森

          來源:SegmentFault 思否社區(qū)

          前言:什么是spine?

          為了讓初學(xué)者有更加直觀的初步的了解,筆者提供了一個簡單的示意圖如下:

          實際開發(fā)中,由設(shè)計人員提供對應(yīng)的spine編輯器所導(dǎo)出的動畫素材,開發(fā)人員選用對應(yīng)的spine運行庫對素材進行消費和上屏渲渲染,便是spine所做的事,相比gif、css幀動畫、apng具備更加強大的靈活性。

          簡單比較如下:


          GIF由于其本身的色彩限制,一般不能滿足設(shè)計的要求,因此目前大多采用CSS幀動畫和APNG的方式處理頁面動畫,小區(qū)域動畫采用apng,大區(qū)域動畫可以考慮采用CSS幀動畫或JS動畫處理。而厘米秀這里由于業(yè)務(wù)本身復(fù)雜且形象裝扮多變,故不得不采用spine2D動畫的方案。

          注釋:

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

          2)、素材圖片:類似雪碧圖,也可單一素材,可導(dǎo)出一張或多張。

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

          一、基本概念

          1、骨架Skeleton:指代的是數(shù)據(jù)的集合,包含構(gòu)成此骨架的所有骨骼、插槽、附件及其他信息。

          2、骨骼bones:以官方示意圖為例,一個人物本身由多個關(guān)節(jié)的骨骼組成。除了根骨骼以外,每個骨骼都有對應(yīng)的父骨骼,骨骼與骨骼之間的關(guān)系最終構(gòu)造成類似樹的結(jié)構(gòu)。


          3、插槽slot:一個骨骼bone下可能有多個slot插槽,每個slot插槽下可以放置一個附件實例。插槽本身的存在有兩個重要的意義,一個是靈活的控制渲染順序,一個是分組同類附件。一個插槽可以有多個附件,但一次只能看到一個。舉個簡單的栗子,圖中手槍所在的位置的插槽是"武器"插槽,而該插槽可以放置不同的武器附件,例如"手槍"附件或"菜刀"附件。
          4、附件attachment:slot插槽內(nèi)當(dāng)前渲染的附件實例,即真實上屏渲染的實物素材。(可能需要對素材做旋轉(zhuǎn)、偏移、縮放甚至網(wǎng)格化mesh處理)。
          5、皮膚skin:skin可以看做是attachment的集合,或者可以認為是attachment的一個映射查詢表,一個人物可以由多套skin,通過切換skin的方式去查詢不同的附件映射表,便可以變相的實現(xiàn)人物的全身換裝。
          其他相關(guān)概念:
          關(guān)鍵幀:
          在編輯器中,動畫是借助關(guān)鍵幀完成的,從開始到結(jié)束的過渡動畫,由spine補間處理。
          權(quán)重與網(wǎng)格:
          權(quán)重用于將網(wǎng)格頂點綁定到一個或多個骨骼。變換骨骼時,頂點也會隨之變換。權(quán)重令網(wǎng)格能夠隨著操縱骨骼而自動變形,從而讓原本復(fù)雜的網(wǎng)格變形動畫變得與骨骼動畫一樣簡單。
          附件類型:
          1、區(qū)域附件:普通的圖片展示附件。
          2、點附件:空間中的一個點和旋轉(zhuǎn),相比骨頭的優(yōu)勢可以為不同的皮膚設(shè)置更改位置和旋轉(zhuǎn),例如不同的槍從不同的位置射擊。
          3、網(wǎng)格附件:支持在圖片內(nèi)設(shè)置多邊形,之后可操縱多邊形的頂點,以有效的方式讓圖片彎曲和變形。
          4、邊界框附件:附加到骨骼上的多邊形,骨骼變化的時候也會隨之變形,可用于撞擊檢測,創(chuàng)建物理主體等。
          5、剪裁附件:剪裁功能讓你可以定義一個多邊形區(qū)域,與邊界框附件類似,它會屏蔽繪制順序中的其他插槽。
          6、路徑附件:用于設(shè)置路徑。
          其中在業(yè)務(wù)中比較常用到的是區(qū)域附件和網(wǎng)格附件。
          三種約束:
          1、IK約束:反向動力學(xué)約束 子骨頭終點固定的場景。
          2、變換約束:變換約束指的是將對骨骼的世界旋轉(zhuǎn)、移動縮放等復(fù)制到多個骨骼上。
          3、路徑約束:使用路徑來調(diào)整骨骼變換,骨骼可以沿著路徑,也可以調(diào)整旋轉(zhuǎn)以指向路徑。

          二、spine架構(gòu)和核心類解讀

          spine整體架構(gòu)分層如下:
          spine核心類如下:


          讀懂上面這張官方所提供的類圖,將會對spine的整體架構(gòu)設(shè)計有更加明確的了解和認識。
          1、Loading模塊:是針對資源加載的處理,一個spine形象的骨架信息導(dǎo)出后,一般會導(dǎo)出為json或者二進制文件的形式,由于json形式純文本文件過大,所以官方提供了二進制文件導(dǎo)出的形式,并且輔以運行庫的代碼針對二進制文件進行解析。其次,Loading模塊中的atlasAttachmentLoader將會負責(zé)atlas文件的解析,由于atlas文件本身是字符串的形式,內(nèi)部包含雪碧圖中素材的位置信息,所以需要解析后與素材建立”關(guān)聯(lián)關(guān)系“。例如:Eyes-close素材在picture1.png圖片中的x,y位置 旋轉(zhuǎn)角度為z,而構(gòu)造出來的這種映射關(guān)系將用于被實例化attachment的時候消費。
          2、Spine Texture Atlas模塊:一張素材圖映射一個atlasPage,一張素材圖中的某個區(qū)域塊映射一個atlasRegion,而region的詳細繪制信息本質(zhì)上已經(jīng)在上個模塊完成。
          3、Rending模塊:由渲染層遍歷slot進行渲染,這里不做詳解,渲染層并非spine核心庫所負責(zé)的部分,上屏渲染可以由canvas、webGL或者其他第三方渲染庫渲染,例如pixijs。
          4、SetupPoseData模塊:或者稱之為SkeletonData模塊,數(shù)據(jù)源從這里輸入進行處理,但是并不是最終數(shù)據(jù),可以理解為這里對數(shù)據(jù)做了一層預(yù)處理,會將骨骼數(shù)據(jù)先處理為boneData,插槽數(shù)據(jù)處理為slotData,當(dāng)然也有部分數(shù)據(jù)不需要被再次處理,在這里,也會根據(jù)前面生成的atlasRegion去構(gòu)造出對應(yīng)的附件實例,存儲進skin中,skin本質(zhì)上為附件映射表。
          其次,數(shù)據(jù)對象本身和實例對象是有差別的。
          數(shù)據(jù)對象是無狀態(tài)的,可在任意數(shù)量的骨架實例間共用。有對應(yīng)實例數(shù)據(jù)的數(shù)據(jù)對象類名稱以“Data”結(jié)尾,沒有對應(yīng)實例數(shù)據(jù)的數(shù)據(jù)對象則沒有后綴,如附件、皮膚及動畫。
          實例對象有許多屬性與數(shù)據(jù)對象相同。數(shù)據(jù)對象中的屬性代表裝配姿勢,通常不會改動。實例對象中的相同屬性表示播放動畫時該實例的當(dāng)前姿勢。每個實例對象保有一個其數(shù)據(jù)對象參考,用于將實例對象重置回裝配姿勢。
          例如,SkeletonData是數(shù)據(jù)對象,而Skeleton是實例對象。
          5、Instance Data模塊:或者稱之為Skeleton模塊,Skeleton實例本身是渲染層上屏渲染的真實直接數(shù)據(jù)源,渲染層將讀取Skeleton實例上的插槽信息,渲染對應(yīng)的附件,在這里,許多數(shù)據(jù)對象已經(jīng)被處理成對應(yīng)的實例對象,例如boneData已經(jīng)被處理為Bone實例,slotData已經(jīng)被處理為Slot實例;其次,如圖中所展示的,Skeleton實例中有兩個比較關(guān)鍵的方法,updateWorldTransform和setToSetUpPose。
          updateWorldTransform為更新世界變換,本質(zhì)是觸發(fā)骨骼位置的計算,由于骨骼位置可能發(fā)生旋轉(zhuǎn)偏移,其對應(yīng)的子骨骼也會受到影響,因此需要更新世界變換重新計算所有骨骼的最新坐標(biāo)位置。
          setToSetUpPose為更新實例到當(dāng)前初始狀態(tài),一般才初始化時或重置人物狀態(tài)時調(diào)用,會將人物形象骨骼裝扮等切換為初始最初的狀態(tài)。
          6、Animation模塊:動畫模塊被單獨抽離,不僅更方便維護和更新實例的狀態(tài)信息,整體架構(gòu)邏輯也簡潔明了,由動畫state實例去觸發(fā)skeleton實例的更新,接下來skeleton實例調(diào)用updateWorldTransform更新世界變化,之后重新上屏渲染。
          一個動畫實例中由多個timeline構(gòu)成,這些timeline實例來自于不同的變種Timeline類,根本上都繼承與底層的TimeLine類,由于一個動畫過程中可能涉及多種變化,因此需要對不同的動畫進行劃分區(qū)別,處理旋轉(zhuǎn)的單獨一條timeline,處理縮放的單獨一條timeline,等等。而雖然不同類別動畫會抽離成不同的timeline,但是最終某個時間節(jié)點生效觸發(fā),所有的timeline"作用"都是同時的。

          三、spine源碼解讀

          1、Slot:存儲插槽的當(dāng)前姿勢。插槽為{@link Skeleton#drawOrder}目的組織附件,并提供存儲附件狀態(tài)的位置。狀態(tài)不能存儲在附件本身中,因為附件是無狀態(tài)的,可以跨多個骨架共享。
          (deform屬性是針對mesh附件的處理信息。)
          (通過setToSetUpPose設(shè)置初始動作)
          (在slot實例里可以直接getAttachment和setAttachment)
          2、SlotData:slot實例里用的數(shù)據(jù)的數(shù)據(jù)格式,包含index、插槽名稱、附件名稱、boneData等。
          3、BoneData:骨頭實例里用的數(shù)據(jù)格式,包含index(骨頭也有index)、骨頭名稱、父骨頭數(shù)據(jù)、骨頭本地轉(zhuǎn)換數(shù)據(jù)、世界轉(zhuǎn)換的模式。
          4、Bone:關(guān)鍵方法updateWorldTransformWith,更新骨骼的世界坐標(biāo)。包含其他的一些方法,世界坐標(biāo)和本地坐標(biāo)的轉(zhuǎn)換,旋轉(zhuǎn)轉(zhuǎn)換等。
          5、SkeletonData: Skeleton實例對應(yīng)的數(shù)據(jù)格式。包含bones、slots、skins、events、animations、各種約束。提供了
          由于是數(shù)據(jù)對象,僅提供了一些findbone、findslot的方法。
          6、Skeleton:根據(jù)data新建Bone和Slot。bone有index按順序建立關(guān)聯(lián)關(guān)系。調(diào)用setToSetupPose將bone和slot設(shè)置到初始位置。會遍歷調(diào)用bone和slot對應(yīng)的方法。updateWorldTransform調(diào)用bone的updateWorldTransform更新骨骼位置。提供了一些Bone、slot、attachment的get、set方法。
          有個update方法,更新time時間。
          7、SkeletonBinary:用于讀取二進制的skeleton文件。
          8、SkeletonBounds:收集每個可見的BoundingBoxAttachment,并計算其多邊形的世界頂點。主要用于碰撞或者命中檢測。由渲染層調(diào)用。
          9、SkeletonCilpping:主要針對ClippingAttachment的處理,由渲染層調(diào)用。
          10、SkeletonJson:用于解析處理spine導(dǎo)出的skeleton json。需要對應(yīng)傳入一個attachmentLoader讓其能構(gòu)造對應(yīng)的attachment實例,處理bone、slots、ik、skins、animation等數(shù)據(jù)。
          處理bone和slot構(gòu)造對應(yīng)的實例data。
          處理skins借助loader生成對應(yīng)附件實例。
          處理 animations生成不同的timeline實例對象。
          最終構(gòu)造出對應(yīng)的SkeletonData實例。
          11、Skin:一套皮膚下的所有attachment都在skin實例下,提供了操作skin和attachment的方法。這里操作的方法相當(dāng)于dictionary,不是改變?nèi)宋镅b扮的。
          12、attachment目錄:各種附件的處理處理方法,繼承于Attachment基類。實際由對應(yīng)的AttachmentLoader調(diào)用對應(yīng)的附件類方法。
          AtlasAttachmentLoader實現(xiàn)了對應(yīng)方法。
          13、Texture:定義了Texture抽象類,定義一些抽象方法需要被實現(xiàn)。
          14、TextureAtlas:針對atlas文本進行解析處理,實現(xiàn)TextureAtlasReader進行逐行讀取,texture
          借助外部傳入的textureLoader回調(diào)來獲取對應(yīng)的紋理。
          每塊小素材對應(yīng)一個TextureAtlasPage,素材信息讀取解析后構(gòu)造對應(yīng)TextureAtlasRegion。
          15、AnimationStateData:存儲AnimationState動畫更改時要應(yīng)用的混合(交叉淡入淡出)持續(xù)時間。
          16、AnimationState:隨著時間調(diào)用動畫,動畫入隊等待播放,允許多個動畫疊加。
          分多個track存儲動畫、區(qū)分不同動畫的timeline,針對event事件的處理邏輯等。
          17、Animation:實現(xiàn)了各種timeline類,Animation負責(zé)調(diào)用apply方法觸發(fā)更新,其apply方法會調(diào)用各個timeline的apply方法更新。timeline類中實現(xiàn)找到對應(yīng)關(guān)鍵幀 決定如何渲染。
          18、AssetManager:靜態(tài)資源管理,包括拉取文本資源、拉取二進制資源、加載紋理。調(diào)用TextureAtlas處理atlas文本等。

          四、渲染庫代碼解讀

          canvas:
          1、AssetManager:沒有做啥,直接沿用core里的AssetManager
          2、canvasTexture:繼承Texture。
          3、SkeletonRender:傳入skeleton數(shù)據(jù),渲染畫布,
          drawImage會遍歷drawOrder中的slot,逐個渲染region附件,借助ctx.drawImage API來裁剪和渲染圖片。
          drawTriangles會計算頂點,渲染調(diào)試模式的綠色線條。
          threejs:
          1、ThreeJsTexture:針對threesjs本身的texture做了一層包裹,處理了一下filter。
          2、MeshBatcher:MeshBatcher繼承自Threejs本身的Mesh。調(diào)用SkeletonMeshMaterial獲取材質(zhì)。
          3、SkeletonMesh:SkeletonMeshMaterial繼承自ShaderMaterial,這里包含了著色器代碼,頂點著色器和片元著色器。
          SkeletonMesh繼承自O(shè)bject3D類。
          核心渲染函數(shù)updateGeometry,skeleton更新世界變化后,調(diào)用渲染函數(shù),遍歷drawOrder。
          RegionAttachment和MeshAttachment會進行渲染,渲染借助MeshBatcher,紋理作為素材傳入batchMaterial。
          webgl:
          1、GLTexture:獲取畫布,渲染對應(yīng)的image到畫布上。
          2、Camera:設(shè)置相機位置
          3、WebGL:定義了ManagedWebGLRenderingContext,其實就是獲取webgl的context上下文。
          4、Input:對元素做事件監(jiān)聽,鼠標(biāo)、touch事件。
          5、Shader:自行實現(xiàn)的著色器,片元和頂點。
          6、SkeletonRenderer:負責(zé)skeleton的上屏渲染,渲染函數(shù)需要借助PolygonBatcher來上屏渲染,同樣的,只會對RegionAttachment和MeshAttachment會進行渲染。
          7、PolygonBatcher:在這里綁定著色器,設(shè)置混合模式,綁定一個Mesh實例對象,Mesh為單獨封裝的mesh類,最終調(diào)用的是Mesh暴露的渲染方法。
          8、Mesh:單獨封裝的Mesh類,允許設(shè)置指數(shù)和頂點,上屏渲染借助context的drawElements和drawArrays方法。
          9、SceneRenderer:最上層的調(diào)用類,實例化batcher、webgl上下文、shader,實例化SkeletonRenderer,暴露不同的渲染方法,包括drawSkeleton,drawSkeletonDebug、drawTexture、drawRegion等。

          五、spine渲染整體流程圖

          根據(jù)前面的介紹,我們對基本概念有所了解,并且了解了spine的整體架構(gòu)設(shè)計,針對核心模塊進行了介紹,同時對spine核心庫源碼以及渲染層源碼的關(guān)鍵邏輯進行解讀,可以整理出spine渲染的整體流程圖如下:
          看到這里相信你對spine的整體架構(gòu)設(shè)計,渲染流程都已經(jīng)有了大致的了解,接下來在明確了底層內(nèi)部的處理流程后,我們的下一步工作是實現(xiàn)換裝和換動作API,具體如何實現(xiàn),請聽下回分解!


          點擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開更多互動和交流,掃描下方”二維碼“或在“公眾號后臺回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -


          瀏覽 188
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码精品一区二区三区四区找到 | 欧美精品一级二级A片 | 黄色视频大全在线免费观看 | 一道本一区二区三区在线视频 | 免费人成在线 |