Cocos Creator 3.0 實(shí)現(xiàn)折紙效果,僅占用一個(gè) DrawCall !
效果

實(shí)現(xiàn)
整體思路
初始化一個(gè)多邊形。 折疊后分割成兩個(gè)多邊形。 如果需要繼續(xù)分割,對場上的所有多邊形進(jìn)行折疊,折疊出新的多邊形的層級正好與原來的相反。

所以,所有的計(jì)算和渲染都可以轉(zhuǎn)換成對一個(gè)多邊形的操作。
為了簡化計(jì)算,我們約定初始化的多邊形為凸多邊形。這么做有幾個(gè)好處。
折疊后生成的仍是凸多邊形,并且對于每個(gè)多邊形只會折疊出兩個(gè)凸多邊形
渲染時(shí),分割凸多邊形為三角形特別方便,即能快速計(jì)算出頂點(diǎn)索引
計(jì)算
主要分為三塊
多邊形分割 線線交點(diǎn) 軸對稱
分割

分割
當(dāng)夾角大于90度時(shí),該頂點(diǎn)正好是折疊多邊形的頂點(diǎn)。
當(dāng)夾角等于90度時(shí),該頂點(diǎn)是兩個(gè)多邊形的頂點(diǎn)。
當(dāng)夾角小于90度時(shí),該頂點(diǎn)是底部多邊形的頂點(diǎn)。
const dotValue = temp_v2_vector.dot(temp_v2_vector_3)
if (Math.abs(dotValue) === 0) {
// 剛好在點(diǎn)上
} else if (dotValue > 0) {
// 在前面
} else {
// 在后面
}
交點(diǎn)

交點(diǎn)
直線上的一點(diǎn)可以用點(diǎn)和向量表示。
直線上的點(diǎn)
Cramer's Rule)求出交點(diǎn)。function linelinePoint(p1: Vec2, p1Dir: Vec2, p2: Vec2, p2Dir: Vec2) {
const a1 = p1Dir.x, b1 = -p2Dir.x, c1 = p2.x - p1.x
const a2 = p1Dir.y, b2 = -p2Dir.y, c2 = p2.y - p1.y
const d = a1 * b2 - a2 * b1,
d1 = c1 * b2 - c2 * b1,
d2 = a1 * c2 - c1 * a2
const t1 = d1 / d, t2 = d2 / d
return [t1, t2]
}
t1,這個(gè)t1不僅可以用來求出頂點(diǎn)坐標(biāo),也可以求出相交的紋理坐標(biāo)。const posSpilt = Vec2(pos.x + dir.x * t1, pos.y + dir.y * t1)
const uvSpilt = Vec2(uv.x + uvdir.x * t1, uv.y + uvdir.y * t1)
對稱點(diǎn)

求出該頂點(diǎn)與中點(diǎn)的向量 求出該點(diǎn)在觸摸方向的單位向量的投影(點(diǎn)乘),這正好是距離的一半 求出對稱點(diǎn)坐標(biāo)(距離乘方向向量+起始點(diǎn)坐標(biāo))

Vec2.subtract(temp_v2_vector_4, temp_v2_pos, pos)
const dotLength = temp_v2_vector_4.dot(temp_v2_vector) * 2
temp_v2_pos_2.set((pos.x + temp_v2_vector.x * dotLength), pos.y + temp_v2_vector.y * dotLength)
渲染

Assembler的方式組裝頂點(diǎn)數(shù)據(jù)。將引擎中的 Sprite-simple組裝器拷貝出來,作為自己的組裝器模板。新建一個(gè)類繼承 Sprite,并設(shè)置它的組裝器到自己的組裝器創(chuàng)建變量頂點(diǎn)數(shù)組,紋理數(shù)組。 編寫組裝器邏輯
// 僅限凸多邊形
@ccclass('PolygonSprite')
export class PolygonSprite extends Sprite {
@property({ type: [Vec2] })
protected _vertices: Vec2[] = [new Vec2(-100, -100), new Vec2(100, -100), new Vec2(100, 100), new Vec2(-100, 100)];
// 省略部分代碼
@property({ type: [Vec2] })
protected _uvs: Vec2[] = [new Vec2(0, 0), new Vec2(1, 0), new Vec2(1, 1), new Vec2(0, 1)];
// 省略部分代碼
protected _flushAssembler() {
//指向自定義的組裝器
let assembler = polygonAssembler;
if (this._assembler !== assembler) {
this.destroyRenderData();
this._assembler = assembler;
}
// 省略部分代碼
}
}
// 保存頂點(diǎn)數(shù)據(jù)
updateVertexData(sprite: PolygonSprite) {
//中間變量
const renderData = sprite.renderData;
if (!renderData) {
return;
}
renderData.vertexCount = renderData.dataLength = sprite.vertices.length
// 三角形數(shù)量 = 頂點(diǎn)數(shù) - 2
// 索引數(shù)量 = 三角形數(shù)量X3
renderData.indicesCount = (renderData.vertexCount - 2) * 3
renderData.vertDirty = false;
for (let i = 0; i < sprite.vertices.length; ++i) {
const xy = sprite.vertices[i];
renderData.data[i].x = xy.x
renderData.data[i].y = xy.y
}
},
updateUvs(sprite: PolygonSprite) {
const renderData = sprite.renderData!;
//實(shí)際uv
const uv = sprite.spriteFrame!.uv;
// 左 下 上 右
const l = uv[0], b = uv[1], t = uv[7], r = uv[6]
for (let i = 0; i < sprite.uvs.length; ++i) {
const uvs = sprite.uvs[i];
renderData.data[i].u = l + (r - l) * uvs.x
renderData.data[i].v = b + (t - b) * uvs.y
}
renderData.uvDirty = false;
},
fillBuffers(sprite: PolygonSprite, renderer: any) {
//省略代碼
// 填充頂點(diǎn)
for (let i = 0; i < renderData.vertexCount; ++i) {
const vert = renderData.data[i];
// 計(jì)算世界坐標(biāo)
vBuf![vertexOffset++] = a * vert.x + c * vert.y + tx;
vBuf![vertexOffset++] = b * vert.x + d * vert.y + ty;
vBuf![vertexOffset++] = vert.z;
// 填充uv
vBuf![vertexOffset++] = vert.u;
vBuf![vertexOffset++] = vert.v;
Color.toArray(vBuf!, sprite.color, vertexOffset);
vertexOffset += 4;
}
// 填充索引
for (let i = 0; i < sprite.vertices.length - 2; ++i) {
const start = i;
iBuf![indicesOffset++] = vertexId;
iBuf![indicesOffset++] = start + 1 + vertexId;
iBuf![indicesOffset++] = start + 2 + vertexId;
}
},
小結(jié)
assembler實(shí)現(xiàn)合批渲染。以上為白玉無冰使用 Cocos Creator 3.0.0 實(shí)現(xiàn) “折紙效果” 的技術(shù)分享,更多精彩請關(guān)注微信公眾號!也歡迎小伙伴們移步“Cocos 中文社區(qū)”一起交流討論。帖子鏈接:https://forum.cocos.org/t/topic/112045
征集令
???????。ocos 現(xiàn)向全體開發(fā)者征集 Creator 3.x 官方文檔內(nèi)容修改建議,登錄“Cocos 中文社區(qū)”說出你的想法吧!地址:
https://forum.cocos.org/t/topic/114798

Cocos 開發(fā)者沙龍來了!6 月 19 日,我們將來到上海,與各位開發(fā)者齊聚一堂!
引擎體重 & 技術(shù)擔(dān)當(dāng) Panda、 CTO & 周邊收集狂林順、首席客服王哲及技術(shù)團(tuán)隊(duì)將一起空降上海,為大家詳解 Cocos Creator 3.x 最新功能及寶藏技術(shù)。
更有華為海思麒麟團(tuán)隊(duì)圖形渲染工程師杜鵬程以及華為工程師夏敏言、《江南百景圖》小游戲版負(fù)責(zé)人大城小胖、樂府資深 Cocos 開發(fā)專家夏凱強(qiáng)、TopOn 廣告產(chǎn)品專家余國強(qiáng)等一眾大佬強(qiáng)勢加盟,帶來超多干貨分享!
此外,我們?yōu)榇蠹規(guī)砹擞埠?/span>現(xiàn)場一對一技術(shù)支持,限額 5 個(gè)團(tuán)隊(duì)。
是的,你沒有看錯(cuò),我們引擎團(tuán)隊(duì)核心成員將全程駐場,你可以攜帶自己的作品和問題同他們進(jìn)行一對一技術(shù)交流,名額有限,趕快掃描下方二維碼報(bào)名吧!
點(diǎn)擊【閱讀原文】跳轉(zhuǎn)至報(bào)名入口,期待你的加入!



