【包教包会】Assembler经典案例第一期——2D实现3D透视翻转(支持原生、可合批、附Demo源码)

一、效果演示

Flip3D

二、如何获取

1、https://gitee.com/szrpf/SpriteFlipper

2、解压,导入cocos creator(版本2.4.13),可以直接运行Demo演示

3、单独复制Demo中的SpriteFlipper.ts到自己项目中

新建一个空节点并添加SpriteFlipper组件,拖一张图片到SpriteFrame里就可以使用了。

三、算法思路

让图片绕着锚点Y轴旋转,呈现近大远小的透视效果。

根据Assembler的基础知识,只要算出图片左下、右下、左上、右上4个顶点旋转后的位置,挪动顶点就能让图片呈现透视效果。这里不清楚的可以参考【包教包会】操控顶点的大师——CocosCreator Assembler保姆级教程

计算顶点翻转后坐标的算法,参考乐府的文章
(原文地址:[https://blog.csdn.net/weixin_44053279/article/details/129565013])
image
任意顶点(x, y, z),沿Y轴旋转A角度后坐标是(xcosA, y, xsinA)
因此,旋转后的点与屏幕的距离z = xsinA
image
从屏幕侧面观察,红点是旋转后的位置,绿点是在屏幕上的投影(也就是我们要计算的坐标)
绿点与观察者的距离 = n
红点与观察者的距离 = n+红点z
根据相似三角形原理,绿点坐标比红点缩小了 n/(n+z)倍:
绿点x = 红点x * n/(n+红点z)
绿点y = 红点y * n/(n+红点z)
由于前面已经算出红点xyz分别是(xcosA, y, xsinA)
因此:
image
n:观察者距离
A:绕Y轴旋转角度
xy:旋转前坐标
旋转前的坐标,可以通过图片宽高+锚点算出,代入公式算出旋转后坐标,运行后的效果:
image
发现图片有些变形
这是由于cc.Sprite是由2个三角形拼成的,虽然四个顶点位置符合近大远小
但是三角形还是正对着摄像机,因为摄像机还是2D正交投影,而不是3D透视投影

这里有2个优化方案:
A、使用shader,让每个像素点的坐标符合近大远小规则。
B、使用Assembler,在图片中间区域插入等间距的顶点,提升图片变形的保真度。

实际上,把方案B三角形数量不断细分,最终效果就是方案A。
由于方案B计算量较小而且支持合批,性能更高,选择方案B。

1)自定义assembler并添加顶点,构成col*row的网格。

2)计算每个顶点旋转前的xy存入point数组,算法如下:
image
网格中第m列第n行的顶点下标 = (col+1)*n+m
由于前面已经算出图片上下左右4个边界,利用插值法lerp(a,b,t) = a+(b-a) * t 可以算出:
第m列第n行顶点x = lerp(左边界,右边界,m/col)
第m列第n行顶点y = lerp(下边界,上边界,n/row)

3)根据前面推导的公式,算出2)中point数组每个顶点旋转A角度后的坐标

4)通过插值法计算顶点UV,重新布线后效果如下:
优化前(1x1网格效果)
image
优化后(3x3网格效果)
image
想要更保真的效果,可以增加网格数量,但也意味着更多的顶点计算量,具体看需求。

如果观察者与图片的距离 < 旋转半径,会导致有些顶点转到观察者身后,导致在屏幕上没有投影。
因此,加入了一个透视程度的参数:
透视程度 = 0代表在无穷远观察,完全不透视
透视程度 = 1代表在1倍旋转半径的位置观察(极限透视)

四、结束语

有不明白的,或者优化建议,可以留言评论,或给我发邮件!

包教包会,你会了吗?

创作不易,请多留言讨论,这样我会有动力发更多好玩的东西上来。

Gitee地址:https://gitee.com/szrpf

EMail地址:27185709@qq.com

推荐链接:

1、【包教包会】零代码实现CocosCreator数据看板,开发游戏的必备神器

2、【包教包会】CocosCreator组件label实现字体合批、变色、排版

3、权重随机算法,解决游戏中一切可控随机(刷怪、掉宝、转盘、抽卡等等)

4、【包教包会】对CocosCreator拖尾组件MotionStreak做了全面优化

5、【包教包会】重写CocosCreator的按钮Button组件,动画、音效、回调逻辑优化

mi

10赞

战略性Mark!!!

大佬太强了 :+1:

image 3.8.2里面改顶点数据是这个效果。。。。。

你可以参考这个,3.x的assembler
https://forum.cocos.org/t/topic/154029

1赞

大佬我在build分包用这个组件提示assembler.updateRenderData读取不到

你放主包试下,先排除是否跟分包有关
另外,你打的是什么平台的包?

H5的分包 主包是个平台 跳转到我这个分包(游戏)

他们问我为什么要趴在地上。

应该没影响的,你编辑器里改属性面板参数,会旋转么

会的 而且浏览器上测试也没问题 就是打包后读取不到这个属性 cannot read properties of null(reading’updateRenderData ')

是打包web-mobile么?打包过程中报错,还是打完包运行的时候报错?

打包没有报错 是打包后 加载这个build包运行报错

是打的web包


我拿demo试了下,没问题啊
你下载的最新版本demo,打个包试试

好的 我试试