为什么大家都那么喜欢用Shader?

引言

哈喽大家好,我是亿元程序员,一位有着8年游戏行业经验的主程。

前几天,在群里看到一条消息:

image

“有没有大佬有放大镜效果。”

字越少,需求越大。

看到这句话,我脑子里的第一反应也是:

上Shader。

刚想回复,我突然想到一个问题:

放大镜明明可以用RenderTexture去实现,为什么第一反应是Shader

其实,不仅仅是放大镜。

  • 水波,用Shader

  • 溶解,用Shader

  • 流光,用Shader

  • 角色受击闪白,也用Shader

仿佛游戏开发里只要效果稍微神秘一点,最后都会收到同一张病历单:

建议Shader,早晚各一次,写完真机观察。

所以本期文章,笔者不打算只给大家扔一份放大镜代码。(扔两份哈哈

我们会在Cocos游戏开发中分别用RenderTextureShader实现同一个效果,再顺便回答标题里的问题:

为什么大家都那么喜欢用Shader?它是真的香,还是看起来比较像大佬?

本文示例工程在文末获取,小伙伴们自行前往。

先别急着写代码,Shader到底是什么?

很多人第一次听到Shader,脑子里出现的是绿色代码雨、复杂公式,以及一位凌晨两点还在调颜色的程序猿。

其实可以先把它理解得粗暴一点:

Shader是运行在GPU上的一段小程序,负责告诉GPU顶点放在哪里、像素最终是什么颜色。

在普通业务代码里,我们经常按对象处理:这个按钮隐藏,那个角色移动,这个弹窗打开。

Shader的思路不太一样。它更像是在说:

“所有经过这里的像素,都按这套规则处理。”

这也是大家喜欢Shader的原因之一。

接下来直接实战。

实战一:RenderTexture,用相机拍

先看不写Shader的方案。

正常情况下Camera把画面渲染到屏幕。但我们也可以让第二台Camera把结果渲染到一张纹理,这张纹理就是 RenderTexture

再把RenderTexture放进一个圆形Mask,链路就变成:

1.为什么要准备隐藏副本?

捕获相机应该只看到需要放大的内容,不能看见放大镜自己。

否则镜片捕获镜片,镜片里又出现镜片,最后得到一个无限套娃效果。

所以示例中准备了:

  • Artwork:主相机正常显示的图片。

  • CaptureArtwork:放在独立Layer,只让捕获相机看到。

  • Lens:圆形MaskRenderTexture内容和镜框。

2.创建 RenderTexture

这里做了三件事:

  • 1. 创建一张256 x 256的纹理。

  • 2. 让捕获相机把结果画进去。

  • 3. 把纹理交给镜片Sprite显示。

3.如何控制放大倍数?

image

orthoHeight 越小,相机看到的范围越少。

假设镜片直径是 220,放大倍数是 2,相机只捕获约 110 高度的内容,再把它铺满 220 的镜片,就得到了2倍放大。

4. 让相机跟随手指

先把触摸点转换到图片内部,再映射到隐藏副本的世界坐标,捕获相机就能找到对应位置。

手指松开后,我们同时隐藏镜片并停用捕获相机。

实战二:Shader,让像素自己走过来

RenderTexture很万能,但为了放大一张静态Sprite,我们增加了副本、CameraLayerRenderTextureMask

也不是不能用,只是有点像为了挖一根葱,认真采购了一台挖掘机。

然而Shader版只需要:

  • 原来的Sprite

  • 一个Material

  • 一段跟随触摸点更新参数的脚本。

这也是Shader受欢迎的另一个原因:

当效果能用像素规则描述时,它往往可以减少额外的操作。

1. UV 是什么?

UV可以理解为图片内部的坐标,范围通常是0~1

  • U表示水平方向,通常从左侧的0到右侧的1

  • V表示垂直方向,也在0~1范围内;具体上下方向可能因纹理来源而不同。

正常情况下,当前像素在什么UV,就去纹理的对应位置取颜色。

放大镜要做的,是让镜片里的UV向圆心靠近:

image

假设 zoom = 2,原来距离圆心 0.2 的采样点,现在只去距离圆心 0.1 的位置取颜色。

更小的纹理范围被铺进同样大的圆里,视觉上自然就放大了。

2. 判断当前像素在不在镜片里

image

计算当前UV到镜片中心的距离:

  • 小于半径:显示放大画面。
  • 大于半径:显示原画面。

3. 把原图和放大图混起来

image

圆外使用 baseColor,圆内使用 magnifiedColor

再判断像素是否位于圆的边缘,混入一层金色,就有了镜框。

**至于镜柄,本示例没有做。**实战最重要的是讲清原理,不是让美术妹子看完以后顺手再提三个优化意见。

4. 脚本只负责传参数

四个数字分别是镜片中心 x、中心 y、半径和放大倍数。

触摸移动时更新圆心,Shader就会在新的位置重新计算。

所以Shader一定比RenderTexture 好吗?

当然不是。

其实在放大镜这个效果中,Shader反而没有RenderTexture灵活。

我们需要根据具体游戏需求去,选择用什么样的技术栈:

优先选择 Shader

  • 放大单张图片、立绘或静态地图。
  • 效果主要是局部变色、扭曲、渐变或纹理采样变化。
  • 希望减少额外节点和相机。

优先选择 RenderTexture

  • 镜片里包含多个节点。
  • 需要看到角色动画、粒子、地图单位等动态内容。
  • 放大对象不是一张简单纹理。

最后再回答文章标题

为什么大家都那么喜欢用Shader?

笔者认为:

  • Shader在特定情况能更好地优化效果。

  • Shader在特定情况能更好地优化性能。

  • Shader在特定情况能更好地展示你的能力。

会用Shader很帅,但知道什么时候不用,更帅。

结语

问题来了:小伙伴们关于"为什么大家都那么喜欢用Shader?"有不同的见解吗?

欢迎在评论区探讨一下。

本文实例工程可通过私信发送“放大镜”获取。


我是"亿元程序员",一位有着8年游戏行业经验的主程。在游戏开发中,希望能给到您帮助,也希望通过您能帮助到大家。

实不相瞒,想要个爱心!请把该文章分享给你觉得有需要的其他小伙伴。谢谢!

推荐文章:

亿元Cocos小游戏实战合集2.0

亿元Cocos小游戏实战合集1.0

老板说最近这款游戏很火让我抄,可是我连玩都玩不明白…

这款值68亿的游戏,你不实战一下吗?安排!

小伙伴说我的拼图游戏用Mask不能合批…

俄罗斯方块谁不会做…啊?流沙版?

最近很火的一个拼图游戏,老板让我用Cocos3.8做一个…

老板说拼图游戏太卷了,让我用Cocos做个3d版本的…

敢不敢挑战用Cocos3.8复刻曾经很火的割绳子游戏?

6赞

shader更加自由,比如如果想要放大镜加上一点仿真实的凸透镜曲面拉伸效果,shader上直接增加一下uv偏移拉伸采样就行了,RT实现就不好扩展了,只能在RT上再加个shader

1赞

:+1: :+1:

tql!!!

实际需求中,背景是一张整图的比较少。。 一般都会有些动画什么的。。。

现在有AI了。shader也不需要学了,直接AI帮写。 :joy: