利用GPU实现翻页效果(分享自知乎网)
2017-09-25 23:14
369 查看
https://zhuanlan.zhihu.com/p/28836892?utm_source=qq&utm_medium=social
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/eafb8f8d7d4916b4be54f1dcdfbf1f87.png)
首发于Runtime
写文章
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/71389ddfd98c7831996194bba337138e.jpg)
陈嘉栋
1 个月前
虽然本文是这个周日下午雨天的临时起意,而演示的Demo也有广告之嫌,但是还是希望各位看官如果觉得有收获的话能够点赞支持。
等一下,修改顶点?
修改网格数据这事没有必要一定要在cpu上进行,我们把这活放到GPU上让它来实现顶点的修改是不是更有趣一点呢。
事实上我们只需要一个Plane,在vs中根据某个属性来修改它顶点的x值和y值。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/0fedf2a96fea346216bd7f443f657f83.png)
而一个最简单的修改方案,就是根据玩家的翻页角度theta来更改顶点的坐标。
那么theta的值是怎么来的呢?一页书的翻动角度在[0,180]之间,变成弧度值就是[0,π],因此我们只需要在脚本中计算玩家拖动的距离和总长度的一个比例ratioValue,将这个ratioValue传递给vs后再和π相乘就求得了theta。
因此,在C#脚本中就需要使用这几个接口了。
这样,在只经过一个pass的情况下,翻页的初步效果已经实现了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/aac30ad1483442fdc4ca5439ae5067e5.jpg)
但是如果翻过90°,可以发现此时不仅第二页没有内容,而且第一页的背面也是空的。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/606ae94260a819330fb00741f38e7955.png)
因此,我们还需要另外2个Pass分别渲染第一页的背面和第二页的内容。
其实很简单,只需要剔除正面,修改一下uv,然后正常的采用背面的纹理_BackTex就ok了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/c6a3a9c1a8633ae4d2cf1f199f25bec3.jpg)
可以看到当书页被翻过90°之后,书页的背面已经能够正确的显示了。
之后就是最后一个pass了,我们用这个pass来显示第二页的内容。
其 实这个pass很简单,仍然是只需要正常的采用背面的纹理_BackTex就ok了。但是这里要注意一个问题,那就是深度的问题。还记得第一个pass 吗?第一个pass绘制了第一页的内容。但是最后一个pass同样也要绘制页面的内容,而且默认情况下深度会覆盖第一个pass绘制的内容。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/677621db5174a54b545c17b86774f2e7.png)
因此,我们要在最后一个pass中正确的处理深度问题,所以我在这里使用了Offset。
OK,shader部分完工了。之后我们只需要在C#脚本中简单的确定当前的页数,来设置相应的前页的tex和后页的tex给shader。
最后的结果大概是这个样子的。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/5ca3d379ec0c2247d596d103ab64905b.jpg)
其实原理也并不复杂,在vs修改顶点位置的时候处理就好了。首先来看看翻页时候页面弯曲的一个大概形状,似乎有点像钟型?
而一说到钟型,各位应该能够想到高斯函数了吧?
所以,接下来我们画一个简单的高斯函数图形。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/da8ba612669c72225e206db738921a9d.png)
(推荐一下这个在线图形计算器)
它大概就长这样。
所以在vs修改顶点坐标时,把这个高斯函数考虑进去,就能够获取一个更自然的效果了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/bcc33bfb2fb134c9f2283d36828148d9.jpg)
不过这里又有一个新的问题需要考虑,就是变成了弧形的书页可能会导致深度上的问题。
这个问题主要是在第二个pass,在翻书和前一页快重合时,因为第二个pass中的某些顶点的深度要大于第一个pass的深度,从而造成穿帮。所以在第二个pass的时候就要加上Offset -1 -1了。
当然,这个demo的代码各位可以在这里获取:
chenjd/Unity-Flip-Book-With-Shader
最后祝各位七夕节快乐。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/eafb8f8d7d4916b4be54f1dcdfbf1f87.png)
首发于Runtime
写文章
利用GPU实现翻页效果
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/71389ddfd98c7831996194bba337138e.jpg)
陈嘉栋
1 个月前
0x00 前言
有一段时间没有更新博客了,在考虑写点什么的时候正好赶上了这个月我的书《Unity 3D脚本编程》又加印了。因此写篇小文聊聊利用shader来实现翻书的效果吧。虽然本文是这个周日下午雨天的临时起意,而演示的Demo也有广告之嫌,但是还是希望各位看官如果觉得有收获的话能够点赞支持。
0x01 Vertex Shader
之前看到过类似“Unity怎么实现类似书本的翻页效果”之类的问题,答案大多是利用现成的插件来实现,这听上去似乎并没有实际上解决这个问题。后来又看到过一些更靠谱的解决方案例如利用UGUI的vertex modifier修改顶点、或者使用骨骼动画。等一下,修改顶点?
修改网格数据这事没有必要一定要在cpu上进行,我们把这活放到GPU上让它来实现顶点的修改是不是更有趣一点呢。
事实上我们只需要一个Plane,在vs中根据某个属性来修改它顶点的x值和y值。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/0fedf2a96fea346216bd7f443f657f83.png)
而一个最简单的修改方案,就是根据玩家的翻页角度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的情况下,翻页的初步效果已经实现了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/aac30ad1483442fdc4ca5439ae5067e5.jpg)
但是如果翻过90°,可以发现此时不仅第二页没有内容,而且第一页的背面也是空的。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/606ae94260a819330fb00741f38e7955.png)
因此,我们还需要另外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了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/c6a3a9c1a8633ae4d2cf1f199f25bec3.jpg)
可以看到当书页被翻过90°之后,书页的背面已经能够正确的显示了。
之后就是最后一个pass了,我们用这个pass来显示第二页的内容。
其 实这个pass很简单,仍然是只需要正常的采用背面的纹理_BackTex就ok了。但是这里要注意一个问题,那就是深度的问题。还记得第一个pass 吗?第一个pass绘制了第一页的内容。但是最后一个pass同样也要绘制页面的内容,而且默认情况下深度会覆盖第一个pass绘制的内容。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/677621db5174a54b545c17b86774f2e7.png)
因此,我们要在最后一个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。
最后的结果大概是这个样子的。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/5ca3d379ec0c2247d596d103ab64905b.jpg)
0x03 Update一下
当然,为了让翻书的效果更自然,为翻动中的书页增加一些弧度似乎是一个不错的选择。其实原理也并不复杂,在vs修改顶点位置的时候处理就好了。首先来看看翻页时候页面弯曲的一个大概形状,似乎有点像钟型?
而一说到钟型,各位应该能够想到高斯函数了吧?
所以,接下来我们画一个简单的高斯函数图形。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/da8ba612669c72225e206db738921a9d.png)
(推荐一下这个在线图形计算器)
它大概就长这样。
所以在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));
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/15/bcc33bfb2fb134c9f2283d36828148d9.jpg)
不过这里又有一个新的问题需要考虑,就是变成了弧形的书页可能会导致深度上的问题。
这个问题主要是在第二个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实现翻页效果
- 利用GPU实现翻页效果
- 2014-11-3Android学习------利用ViewFlipper实现滑动翻页的效果--------GIF动画实现
- iOS动效-利用CATransform3D实现翻页动画效果
- 利用silverlight的导航控件,实现翻页效果
- 利用jQuery实现一个简单的表格上下翻页效果
- 利用silverlight的导航控件,实现翻页效果
- [分享]OpenGL实现的翻页效果
- 分享一个自己利用javascript中的window.setInterval()定时器实现页面背景图片淡入淡出效果
- 利用GPU 实现翻页
- 分享一个自己利用javascript中的window.setInterval()定时器实现页面背景图片变换的特效(同时淡入淡出效果)
- Android利用悬浮按钮实现翻页效果
- 利用数组元素交换技术来实现界面的翻页滑动效果
- iOS动效-利用CATransform3D实现翻页动画效果
- Android 实现书籍翻页效果----原理篇
- 用c#和GDI+实现杂志翻页动画效果
- 利用GDI+基于WIN32实现桌面雪花效果(二)
- orcale利用输出参数返回游标,实现返回数据集效果
- C语言中利用#define和#undef定义初始化数组,实现不同的初始化效果
- 在Android手机上实现阅读器的翻页效果