博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用GPU实现翻页效果
阅读量:6274 次
发布时间:2019-06-22

本文共 2575 字,大约阅读时间需要 8 分钟。

0x00 前言

有一段时间没有更新博客了,在考虑写点什么的时候正好赶上了这个月我的书又加印了。因此写篇小文聊聊利用shader来实现翻书的效果吧。

虽然本文是这个周日下午雨天的临时起意,而演示的Demo也有广告之嫌,但是还是希望各位看官如果觉得有收获的话能够点赞支持。

0x01 Vertex Shader

之前看到过类似“Unity怎么实现类似书本的翻页效果”之类的问题,答案大多是利用现成的插件来实现,这听上去似乎并没有实际上解决这个问题。后来又看到过一些更靠谱的解决方案例如利用UGUI的vertex modifier修改顶点、或者使用骨骼动画。

等一下,修改顶点?
修改网格数据这事没有必要一定要在cpu上进行,我们把这活放到GPU上让它来实现顶点的修改是不是更有趣一点呢。
事实上我们只需要一个Plane,在vs中根据某个属性来修改它顶点的x值和y值。

686199-20170828204055749-1414482085.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的情况下,翻页的初步效果已经实现了。

686199-20170827234823277-735475731.gif
但是如果翻过90°,可以发现此时不仅第二页没有内容,而且第一页的背面也是空的。
686199-20170828203848858-1207657331.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了。

686199-20170828203908530-1433226420.gif
可以看到当书页被翻过90°之后,书页的背面已经能够正确的显示了。

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

686199-20170828203925952-114967989.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。

最后的结果大概是这个样子的。
686199-20170828083222546-1142729719.gif

0x03 Update一下

当然,为了让翻书的效果更自然,为翻动中的书页增加一些弧度似乎是一个不错的选择。

其实原理也并不复杂,在vs修改顶点位置的时候处理就好了。首先来看看翻页时候页面弯曲的一个大概形状,似乎有点像钟型?
而一说到钟型,各位应该能够想到高斯函数了吧?
所以,接下来我们画一个简单的高斯函数图形。
686199-20170829185413921-646008522.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));

686199-20170829182828968-922025541.gif

不过这里又有一个新的问题需要考虑,就是变成了弧形的书页可能会导致深度上的问题。
这个问题主要是在第二个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的代码各位可以在这里获取:

-EOF-

最后打个广告,欢迎支持我的书

欢迎大家关注我的公众号慕容的游戏编程:chenjd01

686199-20170730135126130-2009544236.png

转载地址:http://ajgpa.baihongyu.com/

你可能感兴趣的文章
spring boot集成mongodb最简单版
查看>>
DELL EqualLogic PS存储数据恢复全过程整理
查看>>
《Node.js入门经典》一2.3 安装模块
查看>>
《Java 开发从入门到精通》—— 2.5 技术解惑
查看>>
又是神经网络!还能用来盗取XX女演员信息
查看>>
Ruby 1.9概要(5) 异常
查看>>
《网站性能监测与优化》一2.2 交易网站
查看>>
Ceph分布式存储学习指南1.5 Ceph块存储
查看>>
《Tableau 8权威指南》—— 1.1 Tableau是什么
查看>>
Python语言的创始人解释为什么Python数组的索引从0开始
查看>>
《Netty官方指南》把Netty当做一个通用的库
查看>>
sicp 2.3小结习题尝试解答
查看>>
Linux 性能诊断 perf使用指南
查看>>
实操分享:看看小白我如何第一次搭建阿里云windows服务器(Tomcat+Mysql)
查看>>
Sphinx 配置文件说明
查看>>
数据结构实践——顺序表应用
查看>>
python2.7 之centos7 安装 pip, Scrapy
查看>>
机智云开源框架初始化顺序
查看>>
Spark修炼之道(进阶篇)——Spark入门到精通:第五节 Spark编程模型(二)
查看>>
一线架构师实践指南:云时代下双活零切换的七大关键点
查看>>