利用GPU实现翻页效果
0x00 前言
有一段时间没有更新博客了,在考虑写点什么的时候正好赶上了这个月我的书《Unity 3D脚本编程》又加印了。因此写篇小文聊聊利用shader来实现翻书的效果吧。
虽然本文是这个周日下午雨天的临时起意,而演示的Demo也有广告之嫌,但是还是希望各位看官如果觉得有收获的话能够点赞支持。
0x01 Vertex Shader
之前看到过类似“Unity怎么实现类似书本的翻页效果”之类的问题,答案大多是利用现成的插件来实现,这听上去似乎并没有实际上解决这个问题。后来又看到过一些更靠谱的解决方案例如利用UGUI的vertex modifier修改顶点、或者使用骨骼动画。
等一下,修改顶点?
修改网格数据这事没有必要一定要在cpu上进行,我们把这活放到GPU上让它来实现顶点的修改是不是更有趣一点呢。
事实上我们只需要一个Plane,在vs中根据某个属性来修改它顶点的x值和y值。

而一个最简单的修改方案,就是根据玩家的翻页角度theta来更改顶点的坐标。
float4 flip_book(float4 vertex)
{
...
temp.x = vertex.x * cos(theta);
temp.y = vertex.x * sin(theta);
vertex = temp;
return vertex;
}
那么theta的值是怎么来的呢?一页书的翻动角度在[0,180]之间,变成弧度值就是[0,π],因此我们只需要在脚本中计算玩家拖动的距离和总长度的一个比例ratioValue,将这个ratioValue传递给vs后再和π相乘就求得了theta。
因此,在C#脚本中就需要使用这几个接口了。
IDragHandler, IPointerDownHandler, IPointerUpHandler
这样,在只经过一个pass的情况下,翻页的初步效果已经实现了。

但是如果翻过90°,可以发现此时不仅第二页没有内容,而且第一页的背面也是空的。

因此,我们还需要另外2个Pass分别渲染第一页的背面和第二页的内容。
0x02 3个Pass
ok,接下来我们就来完成第二个pass。
fixed4 frag_flip_back (v2f i) : SV_Target
{
i.uv.x = 1 - i.uv.x;
fixed4 col = tex2D(_BackTex, i.uv);
return col;
}
//翻起来的背面
Pass
{
Cull Front
CGPROGRAM
#pragma vertex vert_flip
#pragma fragment frag_flip_back
ENDCG
}
其实很简单,只需要剔除正面,修改一下uv,然后正常的采用背面的纹理_BackTex就ok了。

可以看到当书页被翻过90°之后,书页的背面已经能够正确的显示了。
之后就是最后一个pass了,我们用这个pass来显示第二页的内容。其实这个pass很简单,仍然是只需要正常的采用背面的纹理_BackTex就ok了。但是这里要注意一个问题,那就是深度的问题。还记得第一个pass吗?第一个pass绘制了第一页的内容。但是最后一个pass同样也要绘制页面的内容,而且默认情况下深度会覆盖第一个pass绘制的内容。

因此,我们要在最后一个pass中正确的处理深度问题,所以我在这里使用了Offset。
//第二页
Pass
{
Cull Back
Offset 1, 1
CGPROGRAM
#pragma vertex vert_next_page
#pragma fragment frag_flip_back
ENDCG
}
OK,shader部分完工了。之后我们只需要在C#脚本中简单的确定当前的页数,来设置相应的前页的tex和后页的tex给shader。
最后的结果大概是这个样子的。

0x03 Update一下
当然,为了让翻书的效果更自然,为翻动中的书页增加一些弧度似乎是一个不错的选择。
其实原理也并不复杂,在vs修改顶点位置的时候处理就好了。首先来看看翻页时候页面弯曲的一个大概形状,似乎有点像钟型?
而一说到钟型,各位应该能够想到高斯函数了吧?
所以,接下来我们画一个简单的高斯函数图形。

(推荐一下这个在线图形计算器)
它大概就长这样。
所以在vs修改顶点坐标时,把这个高斯函数考虑进去,就能够获取一个更自然的效果了。
float flipCurve = exp(-0.1 * pow(vertex.x - 0.5, 2)) * _CurPageAngle;
theta += flipCurve;
temp.x = vertex.x * cos(clamp(theta, 0, pi));
temp.y = vertex.x * sin(clamp(theta, 0, pi));

不过这里又有一个新的问题需要考虑,就是变成了弧形的书页可能会导致深度上的问题。
这个问题主要是在第二个pass,在翻书和前一页快重合时,因为第二个pass中的某些顶点的深度要大于第一个pass的深度,从而造成穿帮。所以在第二个pass的时候就要加上Offset -1 -1了。
//翻起来的背面
Pass
{
Cull Front
Offset -1, -1
CGPROGRAM
#pragma vertex vert_flip
#pragma fragment frag_flip_back
ENDCG
}
当然,这个demo的代码各位可以在这里获取:
chenjd/Unity-Flip-Book-With-Shader
-EOF-
最后打个广告,欢迎支持我的书《Unity 3D脚本编程》
欢迎大家关注我的公众号慕容的游戏编程:chenjd01

利用GPU实现翻页效果的更多相关文章
- 利用GPU实现翻页效果(分享自知乎网)
https://zhuanlan.zhihu.com/p/28836892?utm_source=qq&utm_medium=social 首发于Runtime 写文章 利用GPU实现翻页效果 ...
- css3 利用perspective实现翻页效果和正方体 以及翻转效果
要点: 1 实现3D效果就需要使用perspective属性 1 页面旋转使用css3的rorate 2 使用backface-visibility 实现正面元素翻转之后背面不可见,显示出反面的元素 ...
- webapp应用--模拟电子书翻页效果
前言: 现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过pc访问的趋势.所以,用web程序做出仿原生效果的移动应用,也变得越来越流行了.这种程序也就是我们常说的单页应用程序,它也有一个英文 ...
- 简单做出HTML5翻页效果文字特效
之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transfor ...
- c#翻页效果
用c#和GDI+实现杂志翻页动画效果时间:2010-01-13 blog.csdn.net 周公 - 说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇 ...
- 采用cocos2d-x lua 的listview 实现pageview的翻页效果之上下翻页效果
--翻页滚动效果local function fnScrollViewScrolling( sender,eventType) -- body if eventType == 10 the ...
- css实现翻页效果
如图,鼠标移动到图上,实现右上角翻页的效果,本例主要border边框的设置. 一.基本概念 <html> <head> <style> #demo{ width:0 ...
- turn.js 图书翻页效果
今天用turn.js 做图书的翻页效果遇到问题: 图片路径总是出错 调了一天,总算调出来了 我用的thinkphp,其他的不知道是不是一样 三 个地方要改动: 1.后台查出地址 注意的地方:1.地址要 ...
- (旧)子数涵数·PS ——翻页效果
一.首先在网络上下载一张图片,作为素材.这是我下载的素材,至于为什么选择这张照片呢,当然不是因为自己的一些羞羞的念头啦. 二.打开Photoshop,我使用的版本是CS3(因为CS3所占的磁盘空间较小 ...
随机推荐
- Python面向对象编程(二)
1.继承与派生 上文我们已经说过,Python中一切皆对象.我们从对象中抽取了共同特征和技能,得到了类的概念.类与类之间也有共同特征,我们可以从有共同特征和技能的类中提取共同的技能和特征,叫做父类. ...
- 第2章 rsync算法原理和工作流程分析
本文通过示例详细分析rsync算法原理和rsync的工作流程,是对rsync官方技术报告和官方推荐文章的解释. 以下是本文的姊妹篇: 1.rsync(一):基本命令和用法 2.rsync(二):ino ...
- [补] windows C socket编程——大物实验预约
注 : 心血来潮,想着把这两年没能记录下来的经历,写一波回忆杀.诚然,有些经历十分复杂繁琐,希望能耐下性子,写出好文章来,可惜一时不能全想起来这两年来的种种,就想起来什么便写什么吧. 时间估摸着是大一 ...
- SpringMVC源码情操陶冶-ViewResolver视图解析
简单分析springmvc是如何解析view视图,并返回页面给前端 SpringMVC配置视图解析器 <bean id="viewResolver" class=" ...
- Windows7 下安装 tersorflow
最近看起深度学习的一些知识,想要学习一个框架.在网上看了别人对这些框架的评比后,决定学习 tersorflow.之前一直以为 tersorflow 只可以在 Linux 下安装,出乎意料的是,Wind ...
- (转)linux中项目部署和日志查看
1 查找进程 ps -ef | grep java 查看所有关于java的进程 root 17540 1 0 2009 ? 01:42:27 /usr/java/ ...
- global,$GLOBALS[' '] 全局, 浮动float跟margin的注意事项
$a; global只能声明变量为全局,不能赋值,否则报错未定义:global $a; 相对于$GLOBALS['a'],写法是这样的,所有定义过的变量都存在这里: //浮动float跟margin的 ...
- python爬取百度搜索结果ur汇总
写了两篇之后,我觉得关于爬虫,重点还是分析过程 分析些什么呢: 1)首先明确自己要爬取的目标 比如这次我们需要爬取的是使用百度搜索之后所有出来的url结果 2)分析手动进行的获取目标的过程,以便以程序 ...
- java中什么样的对象能够进入老年代
1.大对象:所谓的大对象是指需要大量连续内存空间的java对象,最典型的大对象就是那种很长的字符串以及数组,大对象对虚拟机的内存分配就是坏消息,尤其是一些朝生夕灭的短命大对象,写程序时应避免. 2.长 ...
- vue基础一
一.vue的编写步骤 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...