- ppt图表坐标轴文字框变大:学校科目——文本框+铅笔素材模板
- 工作总结ppt素材:彩色扁平化PPT目录素材
- ppt编辑数据怎么图表同步更新:六张层级递进关系PPT图表模板下载
- 淡雅ppt背景图片:清新的朦胧背景自然风景PPT背景模板
下面的是PPT教程网给你带来的相关内容:
ppt所有幻灯片切换效果设置:PPT 切换 - 纯 Shader 实现(下)
此文是对PPT 切换 - 纯 实现(上) 的补充,至此,基本实现了所有的PPT切换效果(剩下几个倒不是没思路,只是暴力写出来太繁琐了)
如下图所示,上文实现了红框的内容,本文补充绿框的内容:
目录如下:
下面这张 GIF 展示了 30 个切换效果,本文将介绍后半部分(后面有每个效果单独的高清 GIF)
同样,除了两张转场图片外,没有用到其他纹理。所有形状都是 生成,并且没有开 FBO,保证单次 完成
是用 GLSL 写的,之前跟着 网站和 的教程把 的 API 包了一下,下面这个链接可以获得相关的 和 代码:
下面也同样 只给出片段着色器里面的函数部分,而关于 顶点着色器、着色器的输入输出、宏定义常量 都是一样的,可在上文和上述 链接找到,故省略
二十、帘式
现象:一张图片类似于窗帘往两边展开,随后切换到另一张图片
要点:
1、 模拟窗帘的布料,窗帘的形状主要用sin函数进行模拟ppt所有幻灯片切换效果设置:PPT 切换 - 纯 Shader 实现(下),加上一些噪声进行扰动,使之更自然
2、 用关键帧的思想,实现“布料”的动画,在关键时间戳,定义好布料(纹理坐标)的变换,然后tent函数进行叠加,即进行线性插值
代码:
// tent 函数,用于不同关键帧的线性插值
float triFun(float x, float l, float c, float r)
{
float y1 = x / (c - l) - l / (c - l);
float y2 = x / (c - r) + r / (r - c);
return min(clamp(y1, 0.0, 1.0), clamp(y2, 0.0, 1.0));
}
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
vec3 hash33(vec3 p) {
float n = sin(dot(p, vec3(7, 157, 113)));
return fract(vec3(2097152, 262144, 32768) * n) * 2. - 1.;
}
float tetraNoise(in vec3 p)
{
vec3 i = floor(p + dot(p, vec3(0.333333))); p -= i - dot(i, vec3(0.166666));
vec3 i1 = step(p.yzx, p), i2 = max(i1, 1.0 - i1.zxy); i1 = min(i1, 1.0 - i1.zxy);
vec3 p1 = p - i1 + 0.166666, p2 = p - i2 + 0.333333, p3 = p - 0.5;
vec4 v = max(0.5 - vec4(dot(p, p), dot(p1, p1), dot(p2, p2), dot(p3, p3)), 0.0);
vec4 d = vec4(dot(p, hash33(i)), dot(p1, hash33(i + i1)), dot(p2, hash33(i + i2)), dot(p3, hash33(i + 1.)));
return clamp(dot(d, v * v * v * 8.) * 1.732 + .5, 0., 1.); // Not sure if clamping is necessary. Might be overkill.
}
// 一个 transform 完成单边窗帘纹理坐标的变换,所以在 main 里面要对 0.5 左右分别调用
vec3 transform(vec2 texCoord)
{
vec2 res = texCoord;
// 变换的思想类似于:动画的关键帧,在关键时间点定义好变换形式,然后插值
float t1 = 0.0, t2 = 0.5 / 6.0, t3 = 2.0 / 6.0, t4 = 3.0 / 6.0, t5 = 3.5 / 6.0, t6 = 4.5 / 6.0, t7 = 5.3 / 6.0, t8 = 1.0;
// 对 x 坐标的关键帧变换表达式
float fx1 = 0.0;
float fx2 = 0.5 * pow(res.y, 2.0);
float fx3 = 0.5;
float fx4 = 0.5 + 0.25 * pow(1.0 - res.y, 2.0);
float fx5 = 0.5;
float fx6 = 0.5 - 0.25 * pow(1.0 - res.y, 2.0);
float fx7 = 1.0 - 0.75 * pow(1.0 - res.y, 2.0);
float fx8 = 1.0;
// 对x的关键帧进行插值,使用 tent 函数
float deltaX =
triFun(u_ratio, t1, t1, t2) * (fx1)
+triFun(u_ratio, t1, t2, t3) * (fx2)
+triFun(u_ratio, t2, t3, t4) * (fx3)
+triFun(u_ratio, t3, t4, t5) * (fx4)
+triFun(u_ratio, t4, t5, t6) * (fx5)
+triFun(u_ratio, t5, t6, t7) * (fx6)
+triFun(u_ratio, t6, t7, t8) * (fx7)
+triFun(u_ratio, t7, t8, t8) * (fx8);
// 对 x 坐标进行变换:大幅度的窗帘拉动 and 细微的偏移
res.x = (res.x - deltaX) / (1.0 + 0.2 * u_ratio - deltaX);
res.x = res.x - 0.02 * cos(20.0 * PI * res.x) * deltaX;
// 对 y 坐标的关键帧变换表达式
float fy1 = 0.0;
float fy2 = 0.2 * pow(1.0 - res.x, 2.0);
float fy3 = 0.0;
float fy4 = 0.05 * pow(1.0 - (res.x), 2.0);
float fy5 = 0.0;
float fy6 = 0.05 * pow(1.0 - (res.x), 2.0);
float fy7 = 0.3 * pow(1.0 - (res.x), 2.0);
float fy8 = 0.0;
// 对 y 的关键帧进行插值,使用 tent 函数
float deltaY =
triFun(u_ratio, t1, t1, t2) * (fy1)
+triFun(u_ratio, t1, t2, t3) * (fy2)
+triFun(u_ratio, t2, t3, t4) * (fy3)
+triFun(u_ratio, t3, t4, t5) * (fy4)
+triFun(u_ratio, t4, t5, t6) * (fy5)
+triFun(u_ratio, t5, t6, t7) * (fy6)
+triFun(u_ratio, t6, t7, t8) * (fy7)
+triFun(u_ratio, t7, t8, t8) * (fy8);
// 对 y 坐标进行变换:大幅度的窗帘拉动 and 细微的偏移
res.y = (res.y - 1.0) / (1.0 - deltaY) + 1.0;
res.y = res.y + 0.05 * sin(20.0 * PI * res.x) * deltaX * (1.0 - res.y) * random(vec2(floor(res.x * 20.0), 1.0));
float noise = tetraNoise(vec3(res * vec2(5.0, 0.2), u_ratio * 1.0));
//res.x = res.x - clamp(0.2 * noise * pow(deltaX, 0.5),0.0,res.x);
// 窗帘上形如三角函数的光影变化,和变换后的坐标一同返回
float intensityOffset = 0.2 * cos(20.0 * PI * (res.x - clamp(0.2 * noise * pow(deltaX, 0.5), 0.0, res.x))) * deltaX;
return vec3(res, intensityOffset);
}
void main()
{
vec4 resColor = vec4(1.0, 0.0, 0.0, 1.0);
vec4 texColor2 = texture(u_ourTexture2, texCoord);
// 对右半部分:从 0.5 -> 1.0 映射到 0.0 -> 1.0,经过 transform 后再映射回来
if (texCoord.x > 0.5)
{
vec2 coord = vec2(texCoord.x * 2.0 - 1.0, texCoord.y);
vec3 res = transform(coord);
resColor = texture(u_ourTexture1, vec2(res.x * 0.5 + 0.5, res.y));
resColor = resColor * (1.0 + res.z);
// 对于上一张图超出 0-1 范围的地方,显示下一张图
if (res.x < 0.0 || res.x > 1.0 || res.y < 0.0 || res.y > 1.0)
resColor = texColor2;
}
// 对左半部分:从 0.0 -> 0.5 映射到 1.0 -> 0.0,经过 transform 后再映射回来
if (texCoord.x <= 0.5)
{
vec2 coord = vec2(1.0 - texCoord.x * 2.0, texCoord.y);
vec3 res = transform(coord);
resColor = texture(u_ourTexture1, vec2(0.5 - res.x * 0.5, res.y));
resColor = resColor * (1.0 + res.z);
if (res.x < 0.0 || res.x > 1.0 || res.y < 0.0 || res.y > 1.0)
resColor = texColor2;
}
FragColor = resColor;
};
二十一、悬挂 Drape
现象:一张图片类似一块布从上往下掉落,完成切换
要点:
1、 布往下坠落的过程,需要显示布的背面,且需要选择合适的函数来对布料进行近似
2、 布坠落到底部后,由于惯性,会有轻微的往里偏移ppt所有幻灯片切换效果设置,随后恢复
代码:
// tent 函数,用于不同关键帧的线性插值
float triFun(float x, float l, float c, float r)
{
if (l == c) l = c - 0.0001;
if (r == c) r = c + 0.0001;
float y1 = (x - l) / (c - l);
float y2 = (x - r) / (c - r);
return min(clamp(y1, 0.0, 1.0), clamp(y2, 0.0, 1.0));
}
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
vec3 transform(vec2 texCoord)
{
vec2 res = texCoord;
float t1 = 0.5,t2 = 0.6,t3 = 0.7,t4 = 1.0;
// 变换的思想类似于:动画的关键帧,在关键时间点定义好变换形式,然后插值
// 对 x 坐标的关键帧变换表达式
float fx1_left = 0.0;
float fx2_left = 0.1 * res.y * (1.0 - res.y);
float fx3_left = 0.1 * pow(1.0 - res.y, 2.0);
float fx4_left = 0.0;
float fx1_right = 1.0;
float fx2_right = 1.0 - 0.05 * res.y * (1.0 - res.y);
float fx3_right = 1.0 - 0.05 * pow(1.0 - res.y, 2.0);
float fx4_right = 1.0;
// 对x的关键帧进行插值,使用 tent 函数
float deltaX_left =
triFun(u_ratio, t1, t1, t2) * (fx1_left)
+triFun(u_ratio, t1, t2, t3) * (fx2_left)
+triFun(u_ratio, t2, t3, t4) * (fx3_left)
+triFun(u_ratio, t3, t4, t4) * (fx4_left);
float deltaX_right =
triFun(u_ratio, t1, t1, t2) * (fx1_right)
+triFun(u_ratio, t1, t2, t3) * (fx2_right)
+triFun(u_ratio, t2, t3, t4) * (fx3_right)
+triFun(u_ratio, t3, t4, t4) * (fx4_right);
// 对 x 坐标进行变换
res.x = (res.x - deltaX_left) / (deltaX_right - deltaX_left);
// 对 y 坐标的关键帧变换表达式
float fy1_down = 0.0;
float fy2_down = 0.3 * ((0.2-0.3)*res.x + 0.2);
float fy3_down = 0.5 * ((0.2 - 0.3) * res.x + 0.2);
float fy4_down = 0.0;
float fy1_top = 1.0;
float fy2_top = 1.0;
float fy3_top = 1.0;
float fy4_top = 1.0;
// 对y的关键帧进行插值,使用 tent 函数
float deltaY_down =
triFun(u_ratio, t1, t1, t2) * (fy1_down)
+triFun(u_ratio, t1, t2, t3) * (fy2_down)
+triFun(u_ratio, t2, t3, t4) * (fy3_down)
+triFun(u_ratio, t3, t4, t4) * (fy4_down);
float deltaY_top = 1.0;
// 对 y 坐标进行变换
res.y = (res.y - deltaY_down) / (deltaY_top - deltaY_down);
// 光影变化,和变换后的坐标一同返回
float intensityOffset = 0.0;
return vec3(res, intensityOffset);
}
void main()
{
vec4 resColor = vec4(u_ratio,0.0,0.0,1.0);
vec4 texColor1 = texture(u_ourTexture1, texCoord);
vec4 texColor2 = texture(u_ourTexture2, texCoord);
if (u_ratio < 0.5)
{
float R = pow(clamp(1.0 - u_ratio/0.5,0.0,1.0),2.0);
// 转到画布真实的像素坐标系进行变换
vec2 coord = texCoord;
coord.y = 2.0*R - coord.y;
// 添加光影变化
float intensityOffset = -0.5+2.0*(texCoord.y - R) ;
// 揭开的背面的部分
resColor = texture(u_ourTexture1, coord)*(1.0 + intensityOffset);
//resColor = vec4(1.0+intensityOffset,0.0,0.0,1.0);
if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0)
resColor = texColor1;
if(texCoord.y < R)
resColor = texColor2;
}
else
{
vec3 coord = transform(texCoord);
resColor = texture(u_ourTexture1, coord.xy);
if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0)
resColor = texColor2;
}
FragColor = resColor;
};
二十二、上拉帷幕
现象:一张图片像一张布一样被上拉,从而切换到另一张图
要点:
1、 选择合适的函数,模拟布料的扭曲,同时施加噪声,模拟布料的飘动
代码:
// tent 函数,用于不同关键帧的线性插值
float triFun(float x, float l, float c, float r)
{
if (l == c) l = c - 0.0001;
if (r == c) r = c + 0.0001;
float y1 = (x - l) / (c - l);
float y2 = (x - r) / (c - r);
return min(clamp(y1, 0.0, 1.0), clamp(y2, 0.0, 1.0));
}
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
vec3 hash33(vec3 p) {
float n = sin(dot(p, vec3(7, 157, 113)));
return fract(vec3(2097152, 262144, 32768) * n) * 2. - 1.;
}
float tetraNoise(in vec3 p)
{
vec3 i = floor(p + dot(p, vec3(0.333333))); p -= i - dot(i, vec3(0.166666));
vec3 i1 = step(p.yzx, p), i2 = max(i1, 1.0 - i1.zxy); i1 = min(i1, 1.0 - i1.zxy);
vec3 p1 = p - i1 + 0.166666, p2 = p - i2 + 0.333333, p3 = p - 0.5;
vec4 v = max(0.5 - vec4(dot(p, p), dot(p1, p1), dot(p2, p2), dot(p3, p3)), 0.0);
vec4 d = vec4(dot(p, hash33(i)), dot(p1, hash33(i + i1)), dot(p2, hash33(i + i2)), dot(p3, hash33(i + 1.)));
return clamp(dot(d, v * v * v * 8.) * 1.732 + .5, 0., 1.); // Not sure if clamping is necessary. Might be overkill.
}
float polynomialFun(float x, float p1, float p2, float p3, float p4, float p5, float p6)
{
return p1 * pow(x, 5.0)
+ p2 * pow(x, 4.0)
+ p3 * pow(x, 3.0)
+ p4 * pow(x, 2.0)
+ p5 * pow(x, 1.0)
+ p6 * pow(x, 0.0);
}
vec3 transform(vec2 texCoord)
{
vec2 res = texCoord;
float t1 = 0.0;
float t2 = 0.35;
float t3 = 1.0;
res.y = res.y - clamp((u_ratio - t2) / (t3 - t2), 0.0, 1.0) - u_ratio * 0.1;
// 加一个噪声函数,使之更有灵性
float noise = tetraNoise(vec3(texCoord, u_ratio * 3.0));
// 变换的思想类似于:动画的关键帧,在关键时间点定义好变换形式,然后插值
// 对 x 坐标的关键帧变换表达式
float fx1_left = 0.0;
float fx2_left = 0.03 * pow(1.0 - res.y, 2.0);
float fx3_left = 0.1 + 0.25 * pow(1.0 - res.y, 2.0);
float fx1_right = 1.0;
float fx2_right = 1.0 - 0.03 * (1.0 - res.y);
float fx3_right = 0.9 - 0.3 * (1.0 - res.y);
// 对x的关键帧进行插值,使用 tent 函数
float deltaX_left = 0.0;
deltaX_left =
triFun(u_ratio, t1, t1, t2) * (fx1_left)
+triFun(u_ratio, t1, t2, t3) * (fx2_left)
+triFun(u_ratio, t2, t3, t3) * (fx3_left);
float deltaX_right = 1.0;
deltaX_right =
triFun(u_ratio, t1, t1, t2) * (fx1_right)
+triFun(u_ratio, t1, t2, t3) * (fx2_right)
+triFun(u_ratio, t2, t3, t3) * (fx3_right);
// 对 x 坐标进行变换
res.x = (res.x - deltaX_left) / (deltaX_right - deltaX_left) - 0.04 * noise * pow(u_ratio, 0.5);
// 对 y 坐标的关键帧变换表达式
float polynomialValue = polynomialFun(res.x, -6.407, 18.57, -18.76, 7.581, -0.98, 0.017);
float polynomialGrandientValue = polynomialFun(res.x, 0.0, -6.407 * 5.0, 18.57 * 4.0, -18.76 * 3.0, 7.581 * 2.0, -0.98 * 1.0);
float fy1_down = 0.0;
float fy2_down = 0.1 * res.x * (1.0 - res.x) + 0.2 * polynomialValue - 0.05;
float fy3_down = 0.3 * res.x * (1.0 - res.x) + 1.0 * polynomialValue;
float fy1_top = 1.0;
float fy2_top = 1.0 + 1.5 * res.x * (1.0 - res.x) - 0.1;
float fy3_top = 1.0 + 0.6 * res.x * (1.0 - res.x);
// 对y的关键帧进行插值,使用 tent 函数
float deltaY_down =
triFun(u_ratio, t1, t1, t2) * (fy1_down)
+triFun(u_ratio, t1, t2, t3) * (fy2_down)
+triFun(u_ratio, t2, t3, t3) * (fy3_down);
float deltaY_top =
triFun(u_ratio, t1, t1, t2) * (fy1_top)
+triFun(u_ratio, t1, t2, t3) * (fy2_top)
+triFun(u_ratio, t2, t3, t3) * (fy3_top);
// 对 y 坐标进行变换
res.y = (res.y - deltaY_down) / (deltaY_top - deltaY_down);
res.y = res.y - 0.3 * noise * pow(u_ratio, 0.5);
// 光影变化,和变换后的坐标一同返回
float intensityOffset = 1.5 * polynomialGrandientValue * pow((deltaX_left + 1.0 - deltaX_right), 0.5);
return vec3(res, intensityOffset);
}
void main()
{
vec4 texColor2 = texture(u_ourTexture2, texCoord);
vec3 res = transform(texCoord);// transform 返回变换后的 纹理坐标 和 光影调节值
vec4 resColor = texture(u_ourTexture1, res.xy);
resColor = resColor * (1.0 + res.z);
if (res.x < 0.0 || res.x > 1.0 || res.y < 0.0 || res.y > 1.0)
resColor = texColor2;
FragColor = resColor;
};
二十三、剥离
现象:一张图片像一张纸一样被揭开,显示出另一张图
要点:
1、 此实现类似于(十九-悬挂),假想有一根斜直线,如 y = x – 1,图片背面通过镜像得到,直线右边显示底图,左边显示上面的图
代码:
// 斜直线对于 x 的表达式
float fx(float x)
{
return x - u_width + u_ratio * (u_height + u_width + 100.0);
}
// 斜直线对于 y 的表达式
float gy(float y)
{
return y + u_width - u_ratio * (u_height + u_width + 100.0);
}
void main()
{
vec4 resColor = vec4(u_ratio, 0.0, 0.0, 1.0);
vec4 texColor1 = texture(u_ourTexture1, texCoord);
vec4 texColor2 = texture(u_ourTexture2, texCoord);
// 转到画布真实的像素坐标系进行变换
vec2 coordRealScale = texCoord * vec2(u_width, u_height);
// 用二次函数,对揭开的边缘添加偏移
float xNor = (coordRealScale.x - gy(0.0)) / (u_width - gy(0.0));
float yNor = (coordRealScale.y - 0.0) / (fx(u_width) - 0.0);
if (coordRealScale.x > gy(0.0) && coordRealScale.x < u_width)
coordRealScale.y = coordRealScale.y + 70.0 * xNor * (1.0 - xNor);
if (coordRealScale.y > 0.0 && coordRealScale.y < fx(u_width))
coordRealScale.x = coordRealScale.x - 70.0 * yNor * (1.0 - yNor);
// 沿 y = f(x) 翻转
coordRealScale = vec2(gy(coordRealScale.y), fx(coordRealScale.x));
vec2 coord = coordRealScale / vec2(u_width, u_height);
// 添加光影变化
float intensityOffset = (1.0 - (1.0 - coord.x) * u_width / u_height - coord.y) + 2.0 * u_ratio - 0.1;
// 揭开的背面的部分
resColor = texture(u_ourTexture1, coord) * intensityOffset;
if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0)
resColor = texColor1;
if (coordRealScale.y > fx(coordRealScale.x))
resColor = texColor2;
FragColor = resColor;
};
二十四、库
现象:第一张图先向内旋转,同时另一张图推着进来,最后旋转回来
要点:
1、 近似实现图片的三维变换
2、 实现镜像的效果
代码:
vec2 transform(vec2 texCoord, vec2 xyOffset, float zOffset, vec2 scaleCenter, float theta, vec2 thetaCenter)
{
vec2 res = texCoord;
// xy 位移
res = res - xyOffset;
// z 位移,体现为缩放
res = res - scaleCenter;
res = res * (1.0 + zOffset);
res = res + scaleCenter;
// 旋转
res = res - thetaCenter;
res.x = res.x / (cos(theta) + 0.0001);
res.y = res.y / (1.0 - res.x * sin(theta));
res.x = res.x / (1.0 - res.x * sin(theta));
res = res + thetaCenter;
return res;
}
void main()
{
vec2 screenCenter = vec2(0.5);
vec4 texColor1 = vec4(0.0);
vec4 texColor2 = vec4(0.0);
float intensityOffset = 0.0;
vec2 thetaCenter = vec2(1.0, 0.5);
float t1 = 0.4;
float t2 = 0.7;
if (u_ratio < t1)
{
float R1 = clamp((u_ratio - 0.0) / (t1 - 0.0), 0.0, 1.0);
float zOffset1 = 0.0;
vec2 screenCenter1 = vec2(0.5);
vec2 xyOffset1 = vec2(0.0, 0.0);
float theta1 = -R1 * PI * 0.06;
vec2 coord1 = transform(texCoord, xyOffset1, zOffset1, screenCenter1, theta1, thetaCenter);
if (coord1.y < 0.0)
{
// 倒影的实现
coord1.y = -coord1.y - 0.01;
intensityOffset = -coord1.y * 5.0 - 0.5;
}
texColor1 = texture(u_ourTexture1, coord1) * (1.0 + intensityOffset);
}
if (u_ratio >= t1 && u_ratio < t2)
{
float R2 = clamp((u_ratio - t1) / (t2 - t1), 0.0, 1.0);
float zOffset1 = 0.2 * R2;
vec2 xyOffset1 = vec2(-0.8 * R2, 0.0);
float theta1 = -PI * 0.06;
vec2 coord1 = transform(texCoord, xyOffset1, zOffset1, screenCenter, theta1, thetaCenter);
if (coord1.y < 0.0)
{
coord1.y = -coord1.y - 0.01;
intensityOffset = -coord1.y * 5.0 - 0.5;
}
texColor1 = texture(u_ourTexture1, coord1) * (1.0 + intensityOffset);
float zOffset2 = -0.2 * (1.0 - R2);
vec2 xyOffset2 = vec2(1.0 * (1.0 - R2), 0.0);
float theta2 = -PI * 0.06;
vec2 coord2 = transform(texCoord, xyOffset2, zOffset2, screenCenter, theta2, thetaCenter);
if (coord2.y < 0.0)
{
coord2.y = -coord2.y - 0.01;
intensityOffset = -coord2.y * 5.0 - 0.5;
}
texColor2 = texture(u_ourTexture2, coord2) * (1.0 + intensityOffset);
}
if (u_ratio > t2)
{
float R3 = clamp((u_ratio - t2) / (1.0 - t2), 0.0, 1.0);
float zOffset1 = 0.2 * (1.0 - R3);
vec2 xyOffset1 = vec2(-0.8 - 0.25 * R3, 0.0);
float theta1 = -PI * 0.06 * (1.0 - R3);
vec2 coord1 = transform(texCoord, xyOffset1, zOffset1, screenCenter, theta1, thetaCenter);
if (coord1.y < 0.0)
{
coord1.y = -coord1.y - 0.01;
intensityOffset = -coord1.y * 5.0 - 0.5;
}
texColor1 = texture(u_ourTexture1, coord1) * (1.0 + intensityOffset);
float zOffset2 = 0.0;
vec2 xyOffset2 = vec2(0.0, 0.0);
float theta2 = -PI * 0.06 * (1.0 - R3);
vec2 coord2 = transform(texCoord, xyOffset2, zOffset2, screenCenter, theta2, thetaCenter);
if (coord2.y < 0.0)
{
coord2.y = -coord2.y - 0.01;
intensityOffset = -coord2.y * 5.0 - 0.5;
}
texColor2 = texture(u_ourTexture2, coord2) * (1.0 + intensityOffset);
}
FragColor = texColor1 + texColor2;
};
二十五、立方体 Cube
想象:类似立方体的两面进行旋转切换
要点:
1、 近似实现图片的三维变换。之所以是近似,是因为依我现在的水平来看,在 里面无法对纹理坐标实现和顶点一样的三维变换,特别是旋转和投影,只能是近似的剪切变换,所以会看上去有一些
代码:
vec2 transform(vec2 texCoord, vec2 xyOffset, float zOffset, vec2 scaleCenter, float theta, vec2 thetaCenter)
{
vec2 res = texCoord;
// xy 位移
res = res - xyOffset;
// z 位移,体现为缩放
res = res - scaleCenter;
res = res * (1.0 + zOffset);
res = res + scaleCenter;
// 旋转
res = res - thetaCenter;
res.x = res.x / (cos(theta)+0.0001);
res.y = res.y / (1.0 - res.x * sin(theta));
res.x = res.x / (1.0 - res.x * sin(theta));
res = res + thetaCenter;
return res;
}
void main()
{
vec2 screenCenter = vec2(0.5);
vec2 thetaCenter = vec2(0.5, 0.5);
// 图片 1 从 (0.0,0.0,0.0) 移动到 (-0.5,0.0,0.5),且角度为 从 0 到 -PI/2
float zOffset1 = 0.5 * u_ratio;
vec2 xyOffset1 = vec2(-0.5 * u_ratio,0.0);
float theta1 = -u_ratio * PI * 0.5;
vec2 coord1 = transform(texCoord, xyOffset1, zOffset1, screenCenter, theta1, thetaCenter);
vec4 texColor1 = texture(u_ourTexture1, coord1);
// 图片 2 从 (0.5,0.0,0.5) 移动到 (0.0,0.0,0.0),且角度为 从 PI/2 到 0
float zOffset2 = 0.5 * (1.0-u_ratio);
vec2 xyOffset2 = vec2(0.5 * (1.0 - u_ratio), 0.0);
float theta2 = (1.0-u_ratio) * PI * 0.5;
vec2 coord2 = transform(texCoord, xyOffset2, zOffset2, screenCenter, theta2, thetaCenter);
vec4 texColor2 = texture(u_ourTexture2, coord2);
float R = 1.0 - u_ratio;
if(texCoord.x > R)
FragColor = texColor2;
else
FragColor = texColor1;
};
二十六、门 Door
现象:第一张图像门一样打开,第二张图从小到大显示出来
要点:
1、 近似实现第一张图的旋转,第二张图的缩放,同时进行混合
代码:
vec2 transform(vec2 texCoord, vec2 xyOffset, float zOffset, vec2 scaleCenter, float theta, vec2 thetaCenter)
{
vec2 res = texCoord;
res = res - scaleCenter;
res = res * (1.0 + zOffset);
res = res + scaleCenter;
res = res - thetaCenter;
res.x = res.x / cos(theta);
res.y = res.y / (1.0 - res.x * sin(theta));
res.x = res.x / (1.0 - res.x * sin(theta));
res = res + thetaCenter;
res = res - xyOffset;
return res;
}
void main()
{
float zOffset1 = -1.0 * u_ratio;
vec2 screenCenter = vec2(0.5);
vec4 texColor1 = vec4(1.0, 0.0, 0.0, 1.0);
if (texCoord.x < 0.5)
{
float theta = u_ratio * PI * 0.5;
vec2 thetaCenter = vec2(0.0, 0.5);
vec2 coord1 = transform(texCoord, vec2(0.0, 0.0), zOffset1, screenCenter, theta, thetaCenter);
if (coord1.x > 0.5)
coord1.x = 1.001;
texColor1 = texture(u_ourTexture1, coord1);
}
else
{
float theta = -u_ratio * PI * 0.5;
vec2 thetaCenter = vec2(1.0, 0.5);
vec2 coord1 = transform(texCoord, vec2(0.0, 0.0), zOffset1, screenCenter, theta, thetaCenter);
if (coord1.x < 0.5)
coord1.x = -0.001;
texColor1 = texture(u_ourTexture1, coord1);
}
float zOffset2 = 0.5 * (1.0 - u_ratio);// zOffset从 0.5 -> 0,类似缩放因子从 0.5 -> 1
vec2 coord2 = transform(texCoord, vec2(0.0, 0.0), zOffset2, vec2(0.5), 0.0, vec2(0.0, 0.0));
vec4 texColor2 = texture(u_ourTexture2, coord2);
if (coord2.x < 0.0 || coord2.x > 1.0 || coord2.y < 0.0 || coord2.y > 1.0)
{
//texColor2 = vec4(1.0); // window
texColor2 = vec4(0.0); // door
}
FragColor = mix(texColor1, texColor2, u_ratio);
};
二十七、框 Box
现象:两张图片类似一个方形的框架进行旋转,切换到另一张图
要点:
1、 近似实现图片的三维旋转,思路大致和(二十四-立方体)相同
代码:
vec2 transform(vec2 texCoord, vec2 xyOffset, float zOffset, vec2 scaleCenter, float theta, vec2 thetaCenter)
{
vec2 res = texCoord;
// xy 位移
res = res - xyOffset;
// z 位移,体现为缩放
res = res - scaleCenter;
res = res * (1.0 + zOffset);
res = res + scaleCenter;
// 旋转
res = res - thetaCenter;
res.x = res.x / (cos(theta) + 0.0001);
res.y = res.y / (1.0 - res.x * sin(theta));
res.x = res.x / (1.0 - res.x * sin(theta));
res = res + thetaCenter;
return res;
}
void main()
{
vec2 screenCenter = vec2(0.5);
vec2 thetaCenter = vec2(0.5, 0.5);
float zOffset1 = (-abs(u_ratio - 1.0 / 3.0) + 1.0 / 3.0) * 0.5;
vec2 xyOffset1 = vec2(-0.5 * u_ratio, 0.0);
float theta1 = u_ratio * PI * 0.5;
vec2 coord1 = transform(texCoord, xyOffset1, zOffset1, screenCenter, theta1, thetaCenter);
vec4 texColor1 = texture(u_ourTexture1, coord1);
float zOffset2 = (-abs((1.0 - u_ratio) - 1.0 / 3.0) + 1.0 / 3.0) * 0.5;
vec2 xyOffset2 = vec2(0.5 * (1.0 - u_ratio), 0.0);
float theta2 = -(1.0 - u_ratio) * PI * 0.5;
vec2 coord2 = transform(texCoord, xyOffset2, zOffset2, screenCenter, theta2, thetaCenter);
vec4 texColor2 = texture(u_ourTexture2, coord2);
FragColor = texColor1 + texColor2;
};
二十八、梳理 Comb
现象:图像一条一条向左向右飞出,显示出另一张图片
要点:比较简单的实现,纵向分条即可
代码:
void main()
{
vec4 resColor = vec4(u_ratio, 0.0, 0.0, 1.0);
float halfCombNum = 3.0;
float delay = floor(texCoord.y * halfCombNum * 2.0) / halfCombNum * 0.25; // 0-0.5
float Ry = floor(fract(texCoord.y * halfCombNum) * 2.0);// 0-1-0-1-0-1
float ratio = clamp(u_ratio * 2.0 - delay * 2.0, 0.0, 1.0);
if (1.0 - Ry - ratio + (2.0 * Ry - 1.0) * texCoord.x > 0.0)
resColor = texture(u_ourTexture1, vec2(texCoord.x + (1.0 - 2.0 * Ry) * ratio, texCoord.y));
else
resColor = texture(u_ourTexture2, vec2(texCoord.x, texCoord.y));
FragColor = resColor;
};
二十九、缩放 Zoom
现象:两张图片缩放,一张淡出,一张淡入,实现切换
要点:
1、 实现图片缩放,比较简单的实现
代码:
vec2 transform(vec2 texCoord, float zOffset)
{
vec2 coord = texCoord - vec2(0.5);
coord = coord * (1 + zOffset); // zOffset 此处指z方向的偏移,实际上指代指缩放因子
coord = coord + vec2(0.5);
return coord;
}
void main()
{
float zOffset1 = -0.5 * u_ratio;// zOffset从 0 -> -0.5,类似缩放因子从 1 -> 1.5
vec2 coord1 = transform(texCoord, zOffset1);
vec4 texColor1 = texture(u_ourTexture1, coord1);
float zOffset2 = 0.5 * (1.0 - u_ratio);// zOffset从 0.5 -> 0,类似缩放因子从 0.5 -> 1
vec2 coord2 = transform(texCoord, zOffset2);
vec4 texColor2 = texture(u_ourTexture2, coord2);
FragColor = mix(texColor1, texColor2, u_ratio);
};
三十、碎片 Shred
现象:第一张图被分割成多块碎片,分别往前往后迅速移动,在最远点瞬间切换为另一张图,随后恢复
要点:
1、 随机碎片的生成,使用简单的随机数进行生成,详见函数
2、 近似实现碎片的三维变换
代码:
vec2 transform(vec2 texCoord, vec2 xyOffset, float zOffset, vec2 scaleCenter, float xTheta, vec2 xThetaCenter, float yTheta, vec2 yThetaCenter, float zTheta, vec2 zThetaCenter)
{
vec2 res = texCoord;
float projectPar = 0.8;
// 绕 x 轴旋转
res = res - xThetaCenter;
res.y = res.y / cos(xTheta);
res.y = res.y / (1.0 - projectPar * res.y * sin(xTheta));
res.x = res.x / (1.0 - projectPar * res.y * sin(xTheta));
res = res + xThetaCenter;
// 绕 y 轴旋转
res = res - yThetaCenter;
res.x = res.x / cos(yTheta);
res.y = res.y / (1.0 - projectPar * res.x * sin(yTheta));
res.x = res.x / (1.0 - projectPar * res.x * sin(yTheta));
res = res + yThetaCenter;
// 绕 z 轴旋转
res = res - zThetaCenter;
res = res * vec2(u_width, u_height);
res = vec2(dot(vec2(cos(zTheta), sin(zTheta)), res), dot(vec2(-sin(zTheta), cos(zTheta)), res));
res = res / vec2(u_width, u_height);
res = res + zThetaCenter;
// z 方向位移
res = res - scaleCenter;
res = res * (1.0 + zOffset);
res = res + scaleCenter;
// xy 方向位移
res = res - xyOffset;
return res;
}
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
float random(float inV)
{
return random(vec2(inV));
}
float generateFrag(vec2 texCoord)
{
vec2 coord = texCoord;
float num = 12.0;
float v = ceil(fract(coord.x * num) * 2.0 - 1.0);
float floorV = floor(coord.x * num * 2.0);
coord.x = coord.x + random(floorV) / num * 0.5;
if (coord.y < random(floor(coord.x * num * 2.0)))
v = 1.0 - v;
if (texCoord.x < 0.0 || texCoord.x > 1.0 || texCoord.y < 0.0 || texCoord.y > 1.0)
v = 0.0;
return v;
}
vec4 textureSelect(vec2 coord)
{
vec4 resColor = vec4(0.0);
if (u_ratio < 0.5)
resColor = texture(u_ourTexture1, coord);
else
resColor = texture(u_ourTexture2, coord);
return resColor;
}
void main()
{
vec2 scaleCenter = vec2(0.5);
vec2 xThetaCenter = vec2(0.5);
vec2 yThetaCenter = vec2(0.5);
vec2 zThetaCenter = vec2(0.5);
vec4 resColor1 = vec4(0.0);
vec4 resColor2 = vec4(0.0);
vec2 res1 = texCoord;
vec2 res2 = texCoord;
float zOffset = 0.0;
vec2 xyOffset = vec2(0.0);
float xTheta = -PI * 0.05;
float yTheta = PI * 0.1;
float zTheta = 0.0;
float t1 = 0.3;
float t2 = 0.7;// 保证 t1 + t2 = 1.0,且都在 0-1 之间
if (u_ratio < t1 || u_ratio >= t2)
{
float R1 = (-abs(u_ratio - 0.5) + 0.5) / t1;
xTheta = -PI * 0.05 * R1;
yTheta = PI * 0.1 * R1;
{
zOffset = (0.4) * R1;
res1 = transform(texCoord, xyOffset, zOffset, scaleCenter, xTheta, xThetaCenter, yTheta, yThetaCenter, zTheta, zThetaCenter);
float mask = generateFrag(res1);
resColor1 = textureSelect(res1) * mask;
}
{
zOffset = (0.6) * R1;
res2 = transform(texCoord, xyOffset, zOffset, scaleCenter, xTheta, xThetaCenter, yTheta, yThetaCenter, zTheta, zThetaCenter);
float mask = 1.0 - generateFrag(res2);
resColor2 = textureSelect(res2) * mask;
}
FragColor = mix(resColor2, resColor1, resColor1.a);
}
if (u_ratio >= t1 && u_ratio < t2)
{
float R2 = 1.0 - abs((u_ratio - t1) / (t2 - t1) * 2.0 - 1.0);
{
zOffset = 0.4 - 1.5 * R2;
xyOffset = vec2(0.7, 0.2) * R2;
res1 = transform(texCoord, xyOffset, zOffset, scaleCenter, xTheta, xThetaCenter, yTheta, yThetaCenter, zTheta, zThetaCenter);
float mask = generateFrag(res1);
resColor1 = textureSelect(res1) * mask;
}
{
zOffset = 0.6 + 5.0 * R2;
xyOffset = vec2(-1.5, -0.2) * R2;
res2 = transform(texCoord, xyOffset, zOffset, scaleCenter, xTheta, xThetaCenter, yTheta, yThetaCenter, zTheta, zThetaCenter);
float mask = 1.0 - generateFrag(res2);
resColor2 = textureSelect(res2) * mask;
}
FragColor = mix(resColor2, resColor1, resColor1.a);
}
};
三十一、跌落 Fall
现象:一张图片向里跌落,切换到另一张图片
要点:
1、 对纹理坐标进行扭曲,用多项式函数来近似边缘的扭曲
2、 对图片施加旋转的同时,进行边缘扭曲
代码:
vec2 transform(vec2 texCoord, vec2 xyOffset, float zOffset, vec2 scaleCenter, float theta, vec2 rotateCenter)
{
vec2 res = texCoord;
// 这个场景不需要 z 偏移,故可注去
//res = res - scaleCenter;
//res = res * (1.0 + zOffset);
//res = res + scaleCenter;
// 绕 x 轴旋转结合透视,体现为 x 轴方向的剪切,y轴方向的缩放和剪切,且添加了弯曲因素,使得图片看上去弯曲了
res = res - rotateCenter;
res.y = clamp(res.y / cos(theta), -0.5, 1.5);
float yWrapFact = (0.3 * (1.0 - res.x) * u_ratio);// y 坐标的弯曲,与 x 呈线性变化,体现为左边低一些
res.y = res.y * (1.0 + res.y * sin(theta) + yWrapFact);
float xWrapFact = 0.2 * (1.1 - res.x) * u_ratio * sin((res.y + 0.2 * res.x + 0.1) * PI);// x 坐标的弯曲,用 sin 函数进行干扰
res.x = res.x * (1.0 + (res.y * sin(theta) + xWrapFact));
res = res + rotateCenter;
// 这个场景不需要 xy 偏移,故可注去
// res = res - xyOffset;
return res;
}
void main()
{
vec4 resColor = vec4(1.0, 0.0, 0.0, 1.0);
float zOffset1 = 0.0;
vec2 screenCenter = vec2(0.5);
vec2 xyOffset = vec2(0.0);
vec2 rotateCenter = vec2(0.5, 0.0);
// theta 是一个分段函数,用于控制坠落速度,先线性后三次函数
float b = 0.001;
float a = 0.2;
float theta = b / a * u_ratio * PI * 0.5;
if (u_ratio > a)
theta = (pow((u_ratio - a) / (1.0 - a), 3.0) * (1.0 - b) + b) * PI * 0.5;
vec2 coord1 = transform(texCoord, xyOffset, zOffset1, screenCenter, theta, rotateCenter);
// 控制图片变暗的因子
float fadeRatio = 1.0 - 0.5 * u_ratio;
resColor = fadeRatio * texture(u_ourTexture1, coord1);
// 坠落图片意外的区域,显示第二张图
if (coord1.x < 0.0 || coord1.x > 1.0 || coord1.y < 0.0 || coord1.y > 1.0)
resColor = texture(u_ourTexture2, texCoord);
FragColor = resColor;
};
三十二、翻页
现象:像书本翻页一样,进行图片切换
要点:实现图片右半部分的顺时针旋转,这个本身不属于PPT切换的内容,本意是为了模拟“页面卷曲”然而卷曲效果不好实现,就做了这个翻页效果
代码:
vec2 transform(vec2 texCoord, float theta)
{
vec2 res = texCoord - vec2(0.5, 0.5);
// 执行旋转和投影(投影本质上是剪切)
res.x = res.x / cos(theta);
res.y = res.y / (1.0 - res.x * sin(theta));
res.x = res.x / (1.0 - res.x * sin(theta));
res = res + vec2(0.5, 0.5);
return res;
}
void main()
{
// 图片在z方向上的偏移量
vec2 texCoordAfterTransform = transform(texCoord, -u_ratio * PI);
if (u_ratio < 0.5)
{
if (texCoord.x < 0.5)
FragColor = texture(u_ourTexture1, texCoord);
else
{
if (texCoordAfterTransform.x > 1.0 || texCoordAfterTransform.x < 0.0 || texCoordAfterTransform.y < 0.0 || texCoordAfterTransform.y > 1.0)
FragColor = texture(u_ourTexture2, texCoord);
else
FragColor = texture(u_ourTexture1, texCoordAfterTransform) * (1.0 - u_ratio);
}
}
else
{
if (texCoord.x >= 0.5)
FragColor = texture(u_ourTexture2, texCoord);
else
{
if (texCoordAfterTransform.x > 1.0 || texCoordAfterTransform.x < 0.0 || texCoordAfterTransform.y < 0.0 || texCoordAfterTransform.y > 1.0)
FragColor = texture(u_ourTexture1, texCoord);
else
FragColor = texture(u_ourTexture2, vec2(1.0 - texCoordAfterTransform.x, texCoordAfterTransform.y)) * (u_ratio);
}
}
};
感谢你支持pptjcw.com网,我们将努力持续给你带路更多优秀实用教程!
上一篇:ppt动画效果怎么设置全部出来:【实用小技能】用PPT制作好玩的动画图表! 下一篇:ppt整体动画效果在哪里设置:好绝!手把手教会你 7 种高级感 PPT 动画制作,一个比一个好看
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。