Cocos Creator Shader实践 :手写一个搓扑克牌的效果(五)

弧面区域设计思路

弯曲思路

图中A2区域,就是我们作为弯曲区域的部分。

计算真实对称线

我们继续使用之前的代码:

shader.card.vert.js顶点Shader

shader.card.frag.js片元Shader

首先修改shader.card.vert.js代码,把决定一条直线的三个值改为变量,计算公式再上一节中有提到。
shader.card.vert.js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
module.exports =
`
attribute vec2 a_texCoord;
varying vec2 v_texCoord;

const float UNI_A = 1;
const float UNI_B = 1;
const float UNI_C = -200;
const float UNI_D = 50;
const float PI = 3.1415927;

void main(){
v_texCoord = a_texCoord;
// 坐标
vec4 v = vec4(gl_Vertex);

// 折叠左下角,关于直线UNI_A*v.x + UNI_B*v.y + UNI_C = 0对称
vec4 tmp_pos = vec4(0.0, 0.0, 0.0, 0.0);
if(UNI_A*v.x + UNI_B*v.y + UNI_C <= 0){
// 圆弧半径
float r = UNI_D/PI;
// 圆弧分割线C2值
float UNI_C2 = UNI_C + UNI_D*sqrt(pow(UNI_A,2) + pow(UNI_B,2));
//对称区域
if(UNI_A*v.x + UNI_B*v.y + UNI_C2 <= 0){
// 真实对称线C3值
float UNI_C3 = (UNI_C+UNI_C2)/2;
v.z = 2*r;
tmp_pos.x = v.x - 2*UNI_A*((UNI_A*v.x+UNI_B*v.y+UNI_C3)/(pow(UNI_A,2) + pow(UNI_B,2)));
tmp_pos.y = v.y - 2*UNI_B*((UNI_A*v.x+UNI_B*v.y+UNI_C3)/(pow(UNI_A,2) + pow(UNI_B,2)));
v.x = tmp_pos.x;
v.y = tmp_pos.y;
}
//圆弧区域
else{
}
}

// 图片置中,以图片中心为锚点计算得出偏移量
v.x+=180;
v.y+=70;
v = CC_PMatrix * v;
gl_Position = v;
}`;

效果图

弧面位置计算

我们设定对折过的区域与原平面平行,纵切面如下图:
横切面
周长2*UNI_D = πd 可以得出对折区域Z=d=2*UNI_D/π,下面代码用于补充上一步。

1
v.z = 2*UNI_D/3.1415927;

在上图切面中,半圆弧的任意一点,我们都需要计算出其到两条灰色直线的距离。已知的是弧上一点到弧底的弧长(即顶点到直线L1的距离)。

需要用到一下几个推导的公式:

点到直线的距离公式
点到直线的距离公式
弧长角度转换公式
弧长角度转换公式

弧面区域的设计并不只有这一种方案,大家可以自由发挥,先设计思路,再公式推导。

弧形区域代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//圆弧区域
else{
// 弧长,即顶点到L1(UNI_C)的距离
float d = abs((UNI_A*v.x + UNI_B*v.y + UNI_C)/(sqrt(pow(UNI_A,2) + pow(UNI_B,2))));
// 圆心角,C语言sin,cos等三角函数,参数都是弧度,这里圆心角直接计算弧度
float angle = (d*PI)/UNI_D;
// 圆弧上一点在XY平面的投影,到L1的距离
float D_TO_L1 = r * sin(angle);
// 圆弧上一点到XY平面的距离
float Z_TO_XY = r - r*cos(angle);
//Z坐标
v.z = Z_TO_XY;
//XY坐标,根据斜率计算xy变动值 pow(UNI_B/UNI_A*OFF_SET_X,2) + pow(OFF_SET_X,2) = pow(d - D_TO_L1,2)
float OFF_SET_Y = sqrt(pow(d - D_TO_L1,2)/(1+pow(UNI_B,2)/pow(UNI_A,2)));
float OFF_SET_X = UNI_B/UNI_A*OFF_SET_Y;
v.x+=OFF_SET_X;
v.y+=OFF_SET_Y;
}

效果图:

曲面效果图

好了,大功告成!!
下一节,我们来获取触摸位置,实时计算对称线传参数给Shader,来控制弯折区域的大小。

完整代码下载:
点击下载