有一段时间没有更新博客了,在考虑写点什么的时候正好赶上了这个月我的书《Unity 3D 脚本编程》又加印了。因此写篇小文聊聊利用 shader 来实现翻书的效果吧。
虽然本文是这个周日下午雨天的临时起意,而演示的 Demo 也有广告之嫌,但是还是希望各位看官如果觉得有收获的话能够点赞支持。
之前看到过类似 "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 分别渲染第一页的背面和第二页的内容。
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。
最后的结果大概是这个样子的。
当然,这个 demo 的代码各位可以在这里获取:
chenjd/Unity-Flip-Book-With-Shader
-EOF-
最后打个广告,欢迎支持我的书《Unity 3D 脚本编程》
欢迎大家关注我的公众号慕容的游戏编程:chenjd01
来源: http://www.cnblogs.com/murongxiaopifu/p/7441058.html