cocos creator 2.4.0 渲染流程詳解(四:Assembler )

全文共5000+字,分為8個章節(jié),由本人歷時一周整理而來。由于篇幅問題,將本文分為8個章節(jié)分開發(fā)布。全文 () 詳細描述了cocoscreator 引擎的2.40版本中,web平臺的js部分引擎的渲染流程。請將文章配合源碼一起食用!

?由于我尚在學習引擎源碼中,文章可能有不正確的部分,所以我會不斷更新內容。如有錯誤或補充,請留言交流!


全部章節(jié)鏈接:

一:渲染流程中用到的核心類

二 : 渲染流程詳解

三: RenderFlow 的運行邏輯

四: Assembler 的作用

五: ModelBatcher 數(shù)據(jù)合批

六: 材質系統(tǒng)

七: ForwardRender


四 Assembler 的作用

Assembler 由 RenderComponent 持有,并根據(jù) component 的類型不同,持有不同的 Assembler 的子類,用以處理不同的頂點數(shù)據(jù)??梢韵葟淖詈唵蔚钠胀?d圖片的 SimpleSpriteAssembler 入手了解,了解了基礎的內容,再看其他較為復雜的assembler,可以循序漸進。

4.1 RenderData 與 頂點數(shù)據(jù)格式

為了了解 Assembler的工作機制,需要首先了解下頂點數(shù)據(jù)的格式。Assembler中處理的頂點數(shù)據(jù)保存在 _renderData 中,所以了解 RenderData 的類型很重要。RenderData 的創(chuàng)建需要頂點數(shù)據(jù)的格式,頂點格式描述了單個數(shù)據(jù)體的組成結構。常用的頂點格式是 vfmtPosUvColor ,是 Assembler2D 默認使用的格式。代碼定義如下。

var vfmtPosUvColor = new gfx.VertexFormat([ 
    // 節(jié)點的世界坐標,占2個float32 
    { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, 
    // 節(jié)點的紋理uv坐標,占2個float32
     { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, 
    // 節(jié)點顏色值,占4個uint8 = 1個float32
     { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true }, 
]);

在shader中的attribute變量定義如下,可以很容易找到與頂點格式的對應關系。

CCProgram vs %{ 
precision highp float; 
#include <cc-global> 
#include <cc-local> 
  // 對應vfmtPosUvColor結構里的3個字段 
  // 注意這里a_position是vec3類型,但是vfmtPosUvColor對其自定義了2個float長度。 
  // 所以a_position.z = 0 
  in vec3 a_position; // gfx.ATTR_POSITION 
  in vec2 a_uv0; // gfx.ATTR_UV0 
  in vec4 a_color; // gfx.ATTR_COLOR 
  void main () {   // ...   }
}%

再看下 Assembler2D 中定義的數(shù)據(jù)與頂點格式的關系。

cc.js.addon(Assembler2D.prototype, { 
// vfmtPosUvColor 中,單個數(shù)據(jù)節(jié)點占5個float32,為2+2+1. 
floatsPerVert: 5, 
// 頂點數(shù)量:一個四邊形4個頂點 
verticesCount: 4, 
// 頂點索引數(shù)量:一個四邊形按照對角拆分成2個三角形,2*3 = 6個頂點索引 
indicesCount: 6, 
// uv值的索引偏移量:位置坐標占2個float,所以uv的值的下標從2開始算 
uvOffset: 2, 
// color值的索引偏移量:位置2個float,uv2個float,color的值的下標從4開始算 
colorOffset: 4, 
});

頂點數(shù)據(jù)的結構具象化表示出來如圖:

頂點數(shù)據(jù)的結構

了解到頂點數(shù)據(jù)的格式后,更新數(shù)據(jù)時需要將各種數(shù)據(jù)填入對應的位置就可以了。

updateVerts 方法: 更新頂點數(shù)據(jù),填充 pos.x 和 pos.y。

updateUVs 方法: 更新uv數(shù)據(jù),填充 uv.x 和 uv.y。

updateColor 方法: 更新顏色數(shù)據(jù),填充color。

4.2 updateVerts 更新頂點數(shù)據(jù)

在 SimpleSpriteAssembler 的 udpateVerts 方法里,會計算出紋理中上下左右四個邊距距離中心的距離,數(shù)據(jù)長度為4個。

在 SlicedAssembler 的 udpateVerts 方法里,會計算出紋理中上下左右四個邊距離距離中心的長度,加上九宮格需要的可拉伸的上下左右的四個長度,數(shù)據(jù)長度為8個。

其他的Assembler也一樣。。。

具體計算時,會涉及到紋理的尺寸與偏移量,節(jié)點的大小和縮放量。計算過程可以看各個assembler 中的 udpateVerts 的方法實現(xiàn)。

4.3 updateUVs 更新uv數(shù)據(jù)

updateUVs (sprite) {  
 let uv = sprite._spriteFrame.uv;  
 let uvOffset = this.uvOffset;      
 let floatsPerVert = this.floatsPerVert;      
 let verts = this._renderData.vDatas[0];        
 for (let i = 0; i < 4; i++) {         
        let srcOffset = i * 2;        
        let dstOffset = floatsPerVert * i + uvOffset;   
        verts[dstOffset] = uv[srcOffset];        
        verts[dstOffset + 1] = uv[srcOffset + 1];    
    }    
}

源碼位于 cocos2d\core\renderer\webgl\assemblers\sprite\2d\simple.js 。主要內容是將 cc.SpriteFrame 里的 uv 數(shù)據(jù)復制到 RenderData.vDatas 里。每張圖片4個頂點,每個頂點2個float值(x, y)。

可以看到 SimpleSpriteAssembler 的 updateUvs 方法只是將圖片的 uv 未經處理,全部保存下來。如果是未合圖的圖片,那么獲取的uv值就是[0, 1, 1, 1, 0, 0, 1, 0], 代表左上,右上,左下,右下4個頂點。所以圖片渲染出來會是完整的原圖。那么如果我們想要自定義渲染圖片的一部分,就可以在該方法內自定義了。如何自定義可以參考 SlicedAssembler 九宮格填充,TiledAssembler 平鋪填充等其他的圖片填充格式。

4.4 updateColor 更新顏色數(shù)據(jù)

updateColor (comp, color) {         
  let uintVerts = this._renderData.uintVDatas[0];         
  if (!uintVerts) return;         
  color = color != null ? color : comp.node.color._val;         
  let floatsPerVert = this.floatsPerVert;         
  let colorOffset = this.colorOffset;         
  for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) {             
    uintVerts[i] = color;         
  }     
}

代碼位于 cocos2d\core\renderer\assembler-2d.js。將 cc.Node 的 color 屬性的值填充到 RenderData.uintVDatas 中。

Tips:RenderData 的 uintVDatas 和 vDatas 指向同一片緩存區(qū)域,只是2個代表不同的數(shù)據(jù)視圖,uinitVDatas 以 uinit8 為單元訪問,vDatas 以 float32 為單元訪問。

4.5 頂點索引數(shù)據(jù)

上面主要描述了 RenderData 里的 vDatas 的定義格式和填充方式,而 renderData.iDatas 代表的頂點索引數(shù)據(jù)也需要填入數(shù)據(jù)。

為什么需要頂點索引數(shù)據(jù)?因為GPU渲染需要的數(shù)據(jù)其實是一個個三角形的元片,所以單張矩形圖片,需要被切割成2個三角形,這樣的話關于頂點的數(shù)據(jù)數(shù)量,就變成了6個。為了減少數(shù)據(jù)冗余,每個頂點的數(shù)據(jù)只有一份,但是每個三角形的頂點可以用對應的索引來獲取。

頂點索引規(guī)則
initQuadIndices(indices) { 
// 6個一組(對應1個四邊形)生成索引數(shù)據(jù) 
let count = indices.length / 6; 
for (let i = 0, idx = 0; i < count; i++) {
    let vertextID = i * 4; 
    indices[idx++] = vertextID; 
    indices[idx++] = vertextID+1; 
    indices[idx++] = vertextID+2; 
    indices[idx++] = vertextID+1; 
    indices[idx++] = vertextID+3;
    indices[idx++] = vertextID+2;
  }
}

源碼位于 cocos2d\core\renderer\webgl\render-data.js 。

相關鏈接

  1. 自定義渲染https://docs.cocos.com/creator/manual/zh/advanced-topics/custom-render.html#%E8%87%AA%E5%AE%9A%E4%B9%89-assembler

  2. RenderFlow的性能優(yōu)化http://docs.cocos.com/creator/manual/zh/advanced-topics/render-flow.html#

  3. 自定義渲染合批之自定義頂點格式https://forum.cocos.org/t/demo/95087

  4. 自定義RenderFlow,處理背包等場景下drawcall過多:https://forum.cocos.org/t/ui/80026

  5. 材質系統(tǒng)https://docs.cocos.com/creator3d/manual/zh/material-system/overview.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者。

相關閱讀更多精彩內容

友情鏈接更多精彩內容