https://zhuanlan.zhihu.com/p/28836892?utm_source=qq&utm_medium=social

首发于Runtime

利用GPU实现翻页效果

陈嘉栋

1 个月前

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

最后祝各位七夕节快乐。

利用GPU实现翻页效果(分享自知乎网)的更多相关文章

  1. 利用GPU实现翻页效果

    0x00 前言 有一段时间没有更新博客了,在考虑写点什么的时候正好赶上了这个月我的书<Unity 3D脚本编程>又加印了.因此写篇小文聊聊利用shader来实现翻书的效果吧. 虽然本文是这 ...

  2. css3 利用perspective实现翻页效果和正方体 以及翻转效果

    要点: 1 实现3D效果就需要使用perspective属性 1 页面旋转使用css3的rorate 2 使用backface-visibility 实现正面元素翻转之后背面不可见,显示出反面的元素 ...

  3. webapp应用--模拟电子书翻页效果

    前言: 现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过pc访问的趋势.所以,用web程序做出仿原生效果的移动应用,也变得越来越流行了.这种程序也就是我们常说的单页应用程序,它也有一个英文 ...

  4. 纯css3写的仿真图书翻页效果

    对css3研究越深入,越觉得惊艳.css3说不上是万能的,但是它能实现的效果也超出了我的想象.它的高效率和动画效果的流畅性很多情况下能替代js的作用.个人习惯css3能实现的效果就不会用js,虽然在国 ...

  5. Android用悬浮按钮实现翻页效果

    今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在An ...

  6. 简单做出HTML5翻页效果文字特效

    之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transfor ...

  7. c#翻页效果

    用c#和GDI+实现杂志翻页动画效果时间:2010-01-13 blog.csdn.net 周公 - 说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇 ...

  8. 采用cocos2d-x lua 的listview 实现pageview的翻页效果之上下翻页效果

    --翻页滚动效果local function fnScrollViewScrolling( sender,eventType)    -- body    if eventType == 10 the ...

  9. JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有)

    前言:最近园子里多了许多谈语言.谈环境.谈逼格(格局)的文章,看看笑笑过后,殊不知其实都是然并卵.提升自己的技术才是王道.之前博主分享过多篇bootstrap组件的文章,引起了很多园友的关注和支持,看 ...

随机推荐

  1. SQL 根据IF判断,SET字段值

    当INVOICE_STATUS值为1时,赋值为2,否者赋值为原来的值 UPDATE T_INVOICE SET DOWNLOAD_COUNT = DOWNLOAD_COUNT + 1, INVOICE ...

  2. PHP连接到mysql的方法--mysqli和PDO

    php连接到mysql数据库,经典的方式就是使用mysql_connect(),具体代码如下: mysql_connect($db_host, $db_user, $db_pass) or die(m ...

  3. ggplot2学习总结

  4. 【鸟哥的Linux私房菜】笔记

    操作系统核心的功能! 驱动程序与操作系统的关系 2. [计算机组成之组件] 3.CPU实际要处理的数据完全来自于主存储器,这是一个很重要的概念! 4.CPU是整个计算机系统最重要的部分,那么目前世界上 ...

  5. 【Flask】Sqlalchemy limit, offset slice操作

    ### limit.offset和切片操作:1. limit:可以限制每次查询的时候只查询几条数据.2. offset:可以限制查找数据的时候过滤掉前面多少条.3. 切片:可以对Query对象使用切片 ...

  6. css li 间隙

    如果 li 未浮动,而 li 子元素浮动,则ie6和ie7下会出现间隙,解决办法是给 li 写上css hack      *vertical-align:bottom;

  7. 20145230java实验报告1

    20145230实验一JAVA开发环境熟悉 使用JDK编译.运行简单的JAVA程序 实验要求 •使用JDK编译.运行简单的Java程序: •使用IDEA 编辑.编译.运行.调试Java程序. 实验内容 ...

  8. 5.1深入理解计算机系统——系统级I/O

    一.UNIX I/O     在UNIX系统中有一个说法,一切皆文件.所有的I/O设备,如网络.磁盘都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行.这种将设备映射为文件的方式,允 ...

  9. 13.常见模块re-正则模块

    1.正则 正则表达式是计算机科学的一个概念,正则表通常被用来检索.替换那些符合某个模式(规则)的文本.也就是说使用正则表达式可以在字符串中匹配出你需要的字符或者字符串,甚至可以替换你不需要的字符或者字 ...

  10. 【P2422】良好的感觉(单调栈优化DP//奇怪的暴力)

    话说正解是单调栈优化DP,然而貌似根据某种玄学的推算,这个题暴力出解貌似也是可以的.首先,我们枚举所有的点作为最小点,然后横向展开,遇到更小的就停止...然后再操作一下,看上去时间O(N^2),然而由 ...