一,区域划分
二,关键点定义
三,关键点公式
a是可滑动,的定义为 a = (x,y)
f点固定不变的,定义为f = (width,height)
g定义为a和f的中点,定义为g = ((a.x+f.x)/2,(a.y+f.y)/2))
eh我们设置为af的垂直平分线,有
e = (g.x - (f.y - g.y) * (f.y - g.y) / (f.x - g.x), f.y)
h = (f.x, g.y - (f.x - g.x) * (f.x - g.x) / (f.y - g.y))
曲线cdb是起点为c,控制点为e,终点为b的二阶贝塞尔曲线,有
c = (e.x - (f.x - e.x) / 2, f.y)
b = get_intersection_point(line(ae), line(cj))
d = ((c.x + 2e.x + b.x) / 4, (c.y + 2e.y + b.y) / 4
曲线kij是起点为k,控制点为h,终点为j的二阶贝塞尔曲线,有
j = (f.x, h.y - (f.y - h.y) / 2)
k = get_intersection_point(line(ah), line(cj))
i = ((j.x + 2 h.x + k.x) / 4, (j.y + 2h.y +k.y) / 4)
四,区域公式
B区域
最下一层,最先绘制
area(B) = line(上边界) + line (右边界) + line (下边界) + line(左边界)
C区域
- 区域C理论上应该是由点a,b,d,i,k连接而成的闭合区域,但由于d和i是曲线上的点,我们没办法直接从d出发通过path绘制路径连接b点(i,k同理)
- 区域C是 由直线ab,bd,dj,ik,ak连接而成的区域 减去 与区域A交集部分 后剩余的区域
3.所以先绘制C,然后用A覆盖掉C
area(C) = line(id) + line (db) + line (ba) + line(a,k) + line(k,i)
A区域
可以通过曲线定返回,最后绘制
area(A) = line(fc) + quad (cb,e) + line(ba) + line(ak) + quad(kj,h) +line(jf)
五,Shader
Shader "Custom/PageTurnShader"
{
Properties
{
main_tex ("Texture", 2D) = "white" {}
progress_x ("Progress_x", Range(0, 1)) = 0
progress_y ("Progress_y", Range(0, 1)) = 0
is_up ("Is Up", Int) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent" "RenderType"="Transparent"
}
LOD 200
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2_f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D main_tex;
float progress_x, progress_y;
int is_up;
v2_f vert(appdata v)
{
v2_f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
//获取两条相交线段的相交点
float2 get_intersection_point(float2 line_one_v1, float2 line_one_v2, float2 line_two_v1, float2 line_two_v2)
{
const float x1 = line_one_v1.x;
const float y1 = line_one_v1.y;
const float x2 = line_one_v2.x;
const float y2 = line_one_v2.y;
const float x3 = line_two_v1.x;
const float y3 = line_two_v1.y;
const float x4 = line_two_v2.x;
const float y4 = line_two_v2.y;
float denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
// 检查直线是否平行
if (denominator == 0)
{
denominator = 0.00001;
}
const float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
float point_x = x1 + ua * (x2 - x1);
float point_y = y1 + ua * (y2 - y1);
return float2(point_x, point_y);
}
//二次贝塞尔曲线上给定参数 t(取值范围为 0 到 1)对应的点位置。它接受三个控制点 p0(起点),p2(终点),p1(控制点)通过计算贝塞尔曲线方程得出相应位置的点。
float2 quadratic_bezier_curve(const float2 start, const float2 control, const float2 end, const float index)
{
const float u = 1.0 - index;
const float tt = index * index;
const float uu = u * u;
float2 p = uu * start;
p += 2.0 * u * index * control;
p += tt * end;
return p;
}
//判断点是否在线上
bool intersects(float2 line_p1, float2 line_p2, float2 p)
{
const float dy = line_p2.y - line_p1.y;
if (dy == 0)
{
// 线段是水平的,判断是否在两端点之间
return p.y == line_p1.y && p.x >= min(line_p1.x, line_p2.x) && p.x <= max(line_p1.x, line_p2.x);
}
const float dx = line_p2.x - line_p1.x;
const float slope = dx / dy;
if (line_p1.y > p.y != line_p2.y > p.y && p.x < (p.y - line_p1.y) * slope + line_p1.x)
{
return true;
}
return false;
}
//判断点是否在区域A
bool is_in_a(const float2 f, const float2 c, const float2 b, const float2 e, const float2 a, const float2 k, const float2 j,
const float2 h, const float2 uv_size)
{
// 在区域A内的点数
uint num_points_inside = 0;
if (intersects(f, c, uv_size))
{
num_points_inside++;
}
// 计算曲线上的像素位置
float2 pos = c;
for (float index = 0.0; index <= 1.0; index += 0.01)
{
const float2 pos1 = quadratic_bezier_curve(c, e, b, index);
if (intersects(pos, pos1, uv_size))
{
num_points_inside++;
}
pos = pos1;
}
if (intersects(b, a, uv_size))
{
num_points_inside++;
}
if (intersects(a, k, uv_size))
{
num_points_inside++;
}
pos = k;
for (float index = 0.0; index <= 1.0; index += 0.01)
{
const float2 pos1 = quadratic_bezier_curve(k, h, j, index);
if (intersects(pos, pos1, uv_size))
{
num_points_inside++;
}
pos = pos1;
}
if (intersects(j, f, uv_size))
{
num_points_inside++;
}
return num_points_inside % 2 == 0;
}
// 判断是否在区域B
bool is_in_b(const float2 f, const float2 c, const float2 j, const float2 uv_size)
{
uint num_points_inside = 0;
if (intersects(j, f, uv_size))
{
num_points_inside++;
}
if (intersects(f, c, uv_size))
{
num_points_inside++;
}
if (intersects(c, j, uv_size))
{
num_points_inside++;
}
return num_points_inside % 2 == 1;
}
//判断是否在区域C
bool is_in_c(const float2 i, const float2 d, const float2 b, const float2 a, const float2 k, const float2 uv_size)
{
uint num_points_inside = 0;
if (intersects(i, d, uv_size))
{
num_points_inside++;
}
if (intersects(d, b, uv_size))
{
num_points_inside++;
}
if (intersects(b, a, uv_size))
{
num_points_inside++;
}
if (intersects(a, k, uv_size))
{
num_points_inside++;
}
if (intersects(k, i, uv_size))
{
num_points_inside++;
}
return num_points_inside % 2 == 1;
}
fixed4 frag(const v2_f current) : SV_Target
{
// 获取纹理坐标
const float2 uv = current.uv;
fixed4 col = tex2D(main_tex, uv);
fixed4 no_change_col = col;
//获取屏幕坐标
float2 screen_size = _ScreenParams.xy;
const float screen_width = screen_size.x;
const float screen_height = screen_size.y;
const float2 uv_size = float2(uv.x * screen_width, uv.y * screen_height);
/////////////////////////////////////////////////
//通过改变a点来翻页
const float ax = progress_x;
const float ay = progress_y;
float2 a, f, g, e, h, c, j, b, k, d, i;
a = float2(screen_width * ax, screen_height * ay);
f = screen_size;
if (is_up > 0)
{
f = float2(screen_width, 0);
}
g = (a + f) / 2.0;
float fg_x = f.x - g.x;
if (fg_x == 0)
{
fg_x = 0.0001; // 避免除数为 0 的情况
}
e.x = g.x - (f.y - g.y) * (f.y - g.y) / fg_x;
e.y = f.y;
h.x = f.x;
float fg_y = f.y - g.y;
if (fg_y == 0)
{
// 避免除数为 0 的情况,
if (f.y == 0)//f.y这时不能大于0
{
fg_y = -0.0001;
}
else
{
fg_y = 0.0001;
}
}
h.y = g.y - (f.x - g.x) * (f.x - g.x) / fg_y;
c.x = e.x - (f.x - e.x) / 2.0;
c.y = f.y;
j.x = f.x;
j.y = h.y - (f.y - h.y) / 2.0;
b = get_intersection_point(a, e, c, j);
k = get_intersection_point(a, h, c, j);
d.x = (c.x + 2.0 * e.x + b.x) / 4.0;
d.y = (2.0 * e.y + c.y + b.y) / 4.0;
i.x = (j.x + 2.0 * h.x + k.x) / 4.0;
i.y = (2.0 * h.y + j.y + k.y) / 4.0;
const bool is_in_region_a = is_in_a(f, c, b, e, a, k, j, h, uv_size);
const bool is_in_region_b = true;
const bool is_in_region_c = is_in_c(i, d, b, a, k, uv_size);
if (is_in_region_b)
{
col = fixed4(0.0, 0.0, 0.0, 0.0);
}
if (is_in_region_c)
{
col = fixed4(1.0, 1.0, 1.0, 1.0);
}
if (is_in_region_a)
{
col = no_change_col;
}
return col;
}
ENDCG
}
}
}
网友评论