Assembler自定義頂點數(shù)量

簡單概述:
自定義assembler效床,通過修改傳遞到著色器的頂點數(shù)量剩檀,達(dá)成類似TiledSprite的平鋪效果沪猴。
如圖:

image.png

Assembler的作用是記錄頂點數(shù)據(jù)运嗜,對于普通Sprite組件担租,一般是如下的頂點位置奋救、頂點紋理坐標(biāo)反惕、頂點顏色

image.png

在渲染流中背亥,Assembler主要參與了3個環(huán)節(jié),分別是更新顏色程癌、更新渲染數(shù)據(jù)嵌莉、填充緩沖數(shù)據(jù):


image.png

其中updateColor是由Sprite等渲染組件間接調(diào)用:


image.png

我們今天關(guān)心的就是其中updateRenderData這一環(huán)節(jié)锐峭。
updateRenderData沿癞,更新渲染數(shù)據(jù)椎扬,其實就是更新四個頂點的位置蚕涤、紋理坐標(biāo)铣猩。
最上面的笑臉圖中达皿,一個精靈變成對稱平鋪的2x2個精靈,4個頂點變9個頂點龄寞,2個三角形變8個三角形物邑,我們首先需要更新頂點數(shù)量和頂點索引數(shù)量,以便創(chuàng)建足夠大的緩沖區(qū)

    row:number = 2;
    col = 2;
    /**把一張圖變成平鋪的row*col張 */
    setGird(row:number,col:number){
        this.row = row;
        this.col = col;
        this.verticesCount = (row+1)*(col+1);
        this.indicesCount = 6*row*col;
    }

然后我們處理頂點數(shù)據(jù)拂封,首先是頂點索引冒签,默認(rèn)只有四個頂點的時候萧恕,分割成兩個三角形,索引分別是{0,1,2}票唆,{1,2,3}走趋,這一部分在core/render/webgl/render-data.js下


image.png

但是我們現(xiàn)在有9個頂點簿煌,4個矩形姨伟,8個三角形,所以要重新劃分


image.png

如上圖瞒渠,現(xiàn)在我們的三角形伍玖,從左到右淮摔,從下到上和橙,應(yīng)該是
{0,1,3}{1,3,4},{1,2,4},{2,4,5},{3,4,6},{4,6,7},{4,5,7},{5,7,8}
初始化創(chuàng)建頂點數(shù)據(jù)后造垛,重新更新一下索引緩沖

/**更新頂點索引 */
    _updateIndices () {
        let indices = this._renderData.iDatas[0];
        let indexOffset = 0;
        let _col = this.col;
        let _row = this.row;
        for (let j = 0; j < _row; ++j) {
            for (let i = 0; i < _col; ++i) {
                let start = j * (_col+1) + i;
                indices[indexOffset++] = start;
                indices[indexOffset++] = start + 1;
                indices[indexOffset++] = start + _col + 1;
                indices[indexOffset++] = start + 1;
                indices[indexOffset++] = start + _col + 1;
                indices[indexOffset++] = start + 1 + _col + 1;
            }
        }
    }

然后是更新頂點坐標(biāo)五辽,在assembler-2d.js中杆逗,是先計算出四個頂點的本地坐標(biāo),存到_local中蠕蚜,然后與世界矩陣相乘(native下沒有這一步悔橄,矩陣變換好像是在c++端),得到四個頂點的世界坐標(biāo):

updateWorldVerts (comp) {
        let local = this._local;
        let verts = this._renderData.vDatas[0];

        ////省略若干行
            //矩形四個角的本地坐標(biāo)變換成世界坐標(biāo)
            // left bottom
            verts[vertexOffset] = al + cb + tx;
            verts[vertexOffset + 1] = bl + db + ty;
            vertexOffset += floatsPerVert;
            // right bottom
            verts[vertexOffset] = ar + cb + tx;
            verts[vertexOffset + 1] = br + db + ty;
            vertexOffset += floatsPerVert;
            // left top
            verts[vertexOffset] = al + ct + tx;
            verts[vertexOffset + 1] = bl + dt + ty;
            vertexOffset += floatsPerVert;
            // right top
            verts[vertexOffset] = ar + ct + tx;
            verts[vertexOffset + 1] = br + dt + ty;
       

我們要做的是一樣的事情潮酒,只不過頂點多了一點而已


image.png

仍然是從左到右急黎,從下到上侧到,9個頂點的本地坐標(biāo)為:
{-50,-50},{0,-50},{50,-50},{-50,0},{0,0},{50,0},{-50,50},{0,50},{50,50},

        let vertexOffset = 0;
        let _col = this.col;
        let _row = this.row;
        for(let j=0;j<=_row;j++){
            let _y = vb + j/_row*(vt-vb);
            for(let i=0;i<=_col;i++){
                let _x = vl + i/_col*(vr-vl);

                verts[vertexOffset] = a*_x + c*_y + tx;
                verts[vertexOffset + 1] = b*_x + d*_y + ty;
                vertexOffset += floatsPerVert;
            }
        }

以上代碼的意義就是按照從左到右荣回,從下到上的順序遍歷9個頂點
然后插值出當(dāng)前頂點的本地坐標(biāo)心软,然后模擬一下矩陣乘法,得出世界坐標(biāo)删铃。

計算紋理坐標(biāo)時猎唁,遍歷順序要保持一致诫隅。

紋理有個要注意的點帐偎,因為有些頂點是兩個或者三個矩形公用的,所以頂點紋理坐標(biāo)要注意不能紊亂豁生,對于同一個頂點甸箱,不能在一個矩形里預(yù)期采樣紋理右上角芍殖,卻在隔壁矩形預(yù)期采樣紋理左上角仪际。
應(yīng)該如下如:


image.png

應(yīng)該是左右對稱、上下對稱的变秦。
可以找到規(guī)律框舔,最下面第一行,從左往右依次是0,1,0,1,0……樱溉,第二行從左往右依次是2,3,2,3……

    updateUVs (sprite) {
        let uv = sprite._spriteFrame.uv;
        let uvOffset = this.uvOffset;
        let floatsPerVert = this.floatsPerVert;
        let verts = this._renderData.vDatas[0];
        let _col = this.col;
        let _row = this.row;
        let index = uvOffset;
        
        for(let j=0;j<=_row;j++){
            let arr = j%2==0?[0,1]:[2,3];
            for(let i=0;i<=_col;i++){
                let k = arr[i%2]
                let srcOffset = k * 2;

                verts[index] = uv[srcOffset];
                verts[index + 1] = uv[srcOffset + 1];
                index+=floatsPerVert;
            }
        }
    }

按照同樣的順序遍歷所有頂點福贞,然后找出當(dāng)前頂點使用原紋理哪個角的紋理停士,然后依次賦值u恋技、v

以上基本就搞定了。
設(shè)置不同的行列:


image.png

實際價值比較有限骄崩,主要是學(xué)習(xí)用要拂,加深我對頂點的理解宇弛。后面有空考慮做一個拼圖小游戲源请,通過改變頂點數(shù)量可以實現(xiàn)圖片分割成不同的多邊形碎片谁尸。

下面是完整類:

import HYZSimpleSpriteAssembler from "./HYZSimpleSpriteAssembler";

export default class HYZAssemblerGird extends HYZSimpleSpriteAssembler {
    verticesCount = 4;
    indicesCount = 6;

    init(comp) {
        this.setGird(5,5)
        super.init(comp)
        this._updateIndices();
    }

    row:number = 2;
    col = 2;
    /**把一張圖變成平鋪的row*col張 */
    setGird(row:number,col:number){
        this.row = row;
        this.col = col;
        this.verticesCount = (row+1)*(col+1);
        this.indicesCount = 6*row*col;

    }

    /**更新頂點索引 */
    _updateIndices () {
        let indices = this._renderData.iDatas[0];
        let indexOffset = 0;
        let _col = this.col;
        let _row = this.row;
        for (let j = 0; j < _row; ++j) {
            for (let i = 0; i < _col; ++i) {
                let start = j * (_col+1) + i;
                indices[indexOffset++] = start;
                indices[indexOffset++] = start + 1;
                indices[indexOffset++] = start + _col + 1;
                indices[indexOffset++] = start + 1;
                indices[indexOffset++] = start + _col + 1;
                indices[indexOffset++] = start + 1 + _col + 1;
            }
        }
    }

    updateWorldVertsWebGL(comp) {
        let local = this._local;
        let verts = this._renderData.vDatas[0];

        let matrix = comp.node._worldMatrix;
        let matrixm = matrix.m,
            a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
            tx = matrixm[12], ty = matrixm[13];

        let vl = local[0], vr = local[2],
            vb = local[1], vt = local[3];
        
        let floatsPerVert = this.floatsPerVert;
        let vertexOffset = 0;

        let _col = this.col;
        let _row = this.row;
        for(let j=0;j<=_row;j++){
            let _y = vb + j/_row*(vt-vb);
            for(let i=0;i<=_col;i++){
                let _x = vl + i/_col*(vr-vl);

                verts[vertexOffset] = a*_x + c*_y + tx;
                verts[vertexOffset + 1] = b*_x + d*_y + ty;
                vertexOffset += floatsPerVert;
            }
        }
    }

    updateWorldVertsNative(comp) {
        let local = this._local;
        let verts = this._renderData.vDatas[0];
        let floatsPerVert = this.floatsPerVert;
      
        let vl = local[0],
            vr = local[2],
            vb = local[1],
            vt = local[3];
      
        let index = 0;

        let _col = this.col;
        let _row = this.row;
        for(let j=0;j<=_row;j++){
            let _y = vb + j/_row*(vt-vb);
            for(let i=0;i<=_col;i++){
                let _x = vl + i/_col*(vr-vl);

                verts[index] = _x;
                verts[index+1] = _y;
                index += floatsPerVert;
            }
        }
        
    }

    updateUVs (sprite) {
        let uv = sprite._spriteFrame.uv;
        let uvOffset = this.uvOffset;
        let floatsPerVert = this.floatsPerVert;
        let verts = this._renderData.vDatas[0];
        let _col = this.col;
        let _row = this.row;
        let index = uvOffset;
        
        for(let j=0;j<=_row;j++){
            let arr = j%2==0?[0,1]:[2,3];
            for(let i=0;i<=_col;i++){
                let k = arr[i%2]
                let srcOffset = k * 2;

                verts[index] = uv[srcOffset];
                verts[index + 1] = uv[srcOffset + 1];
                index+=floatsPerVert;
            }
        }
    }
}

其中HYZSimpleSpriteAssembler 是完全模仿core\renderer\webgl\assemblers\sprite\2d\simple.js實現(xiàn)的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末决瞳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子痴颊,更是在濱河造成了極大的恐慌蠢棱,老刑警劉巖甩栈,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玉转,死亡現(xiàn)場離奇詭異殴蹄,居然都是意外死亡饶套,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門怠李,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捺癞,“玉大人构挤,你說我怎么就攤上這事√拼。” “怎么了矾飞?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵洒沦,是天一觀的道長。 經(jīng)常有香客問我瞒津,道長,這世上最難降的妖魔是什么买乃? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮钓辆,結(jié)果婚禮上剪验,老公的妹妹穿的比我還像新娘。我一直安慰自己前联,他們只是感情好功戚,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著似嗤,像睡著了一般啸臀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烁落,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天乘粒,我揣著相機與錄音,去河邊找鬼伤塌。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绑洛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了薪寓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤京革,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后廊勃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡屿脐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年西疤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芭碍。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸳吸,死狀恐怖晌砾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤楣嘁,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站买雾,受9級特大地震影響注盈,放射性物質(zhì)發(fā)生泄漏僚饭。R本人自食惡果不足惜尉间,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一撤蚊、第九天 我趴在偏房一處隱蔽的房頂上張望槽唾。 院中可真熱鬧庞萍,春花似錦钝计、人聲如沸私恬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽久锥。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丰歌,已是汗流浹背晓勇。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工稼稿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留硬猫,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓矮锈,卻偏偏與公主長得像猫缭,于是被迫代替她去往敵國和親葱弟。 傳聞我的和親對象是個殘疾皇子壹店,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容