和 mask 裁剪圖片說拜拜,用上高性能的 mesh + shader 。文章底部獲取完整代碼!
效果預覽:
使用方法:
- 創建一個空節點
- 添加用戶腳本組件
mesh-texture-mask
- 添加圖片
- 添加修改多邊形頂點坐標
實現原理
創建 mesh
mesh
是什么? mesh
是決定一個物體形狀的東西。 例如在二維中可以是正方形、圓形、三角形等;在三維中可以是正方體、球體、圓柱體等。
mesh
初始化需要一個 VertexFormat
對象。這個對象是頂點格式對象。
其中 name
是對應頂點着色器的 attribute
變量的值。 type
對應數據類型,決定了每個數據大小。
num
對應有幾個數據分量(猜的哈哈!)。例如二維坐標和紋理uv坐標一般只有x
和y
兩個分量,所以設置為2;三維坐標有xyz
三個變量,所以值為3;而顏色一般有 rgba
四個分量,所以設置為4。
normalize
表示歸一化。
對於我們的多邊形裁剪圖片,只需要一個二維坐標和一個紋理uv坐標,創建 mesh
參考代碼如下:
const gfx = cc.gfx;
let mesh = new cc.Mesh();
mesh.init(new gfx.VertexFormat([
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
]), this.vertexes.length, true);
計算紋理uv坐標
紋理uv坐標系在左上角,u
軸是向右,v
軸是向下,范圍是 0~1。而我們的坐標系在中間,x
軸向右,y
軸向上。
所以我們可以先求出x,y
在左下角的占比,然后再反轉一下y
軸,轉成uv
坐標系。參考代碼如下。
const vx = (pt.x + this.texture.width / 2 + this.offset.x) / this.texture.width;
const vy = 1.0 - (pt.y + this.texture.height / 2 + this.offset.y) / this.texture.height;
計算頂點索引
首先需要知道一個概念,繪制一個形狀實際上是繪制多個三角形。一個多邊形可以分割成多個三角形,而頂點索引是告訴它如何去繪制這些三角形。
如何將一個多邊形切割成多個三角形?可以采用'耳切法'的方式。把多邊形的一個耳朵切掉,然后再對剩下的多邊形再次切割。
怎么樣的耳朵才能切呢?這個耳朵的頂點需要滿足是凸頂點且沒有其他頂點在這個耳朵里。
如何判斷是凸頂點呢?首先要知道向量外積的定義,表示向量的法向量。方向根據右手法則確定,就是手掌立在a、b所在平面的向量a上,掌心由a轉向b的過程中,大拇指的方向就是外積的方向。
對於cc.Vec2
的外積就是面積,有正負之分,也是根據右手法則確定。
若多邊形ABCDEF頂點以逆時針順序排序的話,AB x BC > 0
表示B點是凸頂點。參考代碼如下。
const v1 = p2.sub(p1);
const v2 = p3.sub(p2);
if (v1.cross(v2) >= 0) {
// 是凸點
}
判斷點D是否在三角形ABC內,可以通過外積計算點與線的位置關系判斷出。
// 判斷一個點是否在三角形內
_testInTriangle(point, triA, triB, triC) {
let AB = triB.sub(triA), AC = triC.sub(triA), BC = triC.sub(triB), AD = point.sub(triA), BD = point.sub(triB);
return (AB.cross(AC) >= 0 ^ AB.cross(AD) < 0) // D,C 在AB同同方向
&& (AB.cross(AC) >= 0 ^ AC.cross(AD) >= 0) // D,B 在AC同同方向
&& (BC.cross(AB) > 0 ^ BC.cross(BD) >= 0); // D,A 在BC同同方向
},
最后把以上綜合起來就可以計算出頂點索引。
小結
以上為白玉無冰使用 Cocos Creator v2.2.2 開發"使用 mesh 實現多邊形裁剪圖片"的技術分享。有想法歡迎留言!如果這篇對你有點幫助,歡迎分享給身邊的朋友。
參考資料:
多邊形分解成三角形算法