Unity游戏开发之实现江南水乡效果
共 3698字,需浏览 8分钟
·
2021-05-14 13:41
作者
:
lxbhahaha
来源
: https://blog.csdn.net/lxbhahaha/article/details/116594119
这两天玩了下《江南百景图》,发现里面物体出现的效果很有意思,想了想有大概的实现思路,于是打算在Unity中尝试实现一下。
1.1. 游戏中的效果
仔细看可以观察到,当一些物体进入摄像机视角之后,并不是直接看到这个物体的。二十先看到绘制出轮廓,然后物品的背景色(黑白),再然后才是完整的物品。并且绘制轮廓和背景色出现的时候是类似于消融的效果。如下图顺序的效果。
1.2. 在Unity中模仿的效果
一开始还在想这个轮廓会不会是用描边做的,但是仔细想想应该不是。一方面这种图片的描边应该做不了在图片内部描边,另一方面,放大之后看到轮廓也是不够清晰,估计就是两层图片。
那么整个思路大概分为两部分:
物体的双层消融效果实现 消融效果的调用
消融效果实现必然是用到shader。而且这里是2D图像,按道理一般应该用sprite,但是sprite的渲染和平时mesh的有些许不太一样,对此我不太了解。所以我还是用3dMesh的形式,用一个quad显示图片。首先需要两张图片,一张是轮廓,一张是颜色。分别容噪声去消融。以及顺便控制图片的颜色和透明度。然后用以0-1的值对应整个流程,通过控制这一个值来控制图片的显示。
大体思路如下图:如何去调用的话,目前有几个想法。
通过OnBecameVisible和OnBecameInvisible函数让物体在被摄像机看到之后,开始将value值从0到1变化,物体离开摄像机之后从1到0。 用一张灰度图代表整个地图,在摄像机内的部分缓慢变为1,摄像机外的部分缓慢变成0,然后直接从shader中读取这个灰度图对应坐标的数字用来控制消融。
方法1对于我来说比较容易实现,但是这样子就意味着每一个物体上都需要挂在一个脚本来控制消融。当场景里面有非常多的物体的时候,不知道性能消耗大不大。方法2的话,自我认为大部分工作都是GPU的,应该效率会高一些。但是我不知道怎么做…
还是用方法1简单做做就好了。
3.1. 图片
首先要有用来显示的图片,分图层画好轮廓和颜色。然后分别导出成png格式的图片。(不会画画,瞎画的)
3.2. shader
我就直接用ShaderGraph连连看了,比较方便。
有一个点,当Remap节点输入值超过InMinMax范围的时候,输出值也会超出OutMinMax的范围,这不是我想要的。于是稍微封装一下搞了一个MyRemap的SubGraph,如下。整体节点的连接如下,就不细说了。
大体就是用世界坐标(加上了一个物体坐标,免得消融的时候相邻的物体都太连贯了)作为噪声的uv。通过各种加减乘除以及Remap(即将0-1里面每部分的值重新映射到相应的值上)实现消融、透明度、黑白彩色(或者可以叫饱和度?)的变换。并且颜色和alpha分开控制。大图不太清晰,下面拆分成几部分放图片。微信搜索公众号 [爱上游戏开发],回复 “资料”,免费领取 200G 学习资料!
3.3. 代码
代码比较简单,不多说了。不知道OnBecameVisible
和OnBecameInvisible
可以去查查API。
控制value值可以向下面一样线性的控制,或者用插值平滑一下。如果用上AnimationCurve也许效果会更好吧。
using UnityEngine;
public class Mix2D : MonoBehaviour
{
private Material _material;
private bool _isSeeing;
private static readonly int Vector1Value = Shader.PropertyToID("Vector1_Value");
private float _value;
public float speed = 0.3f;
private void Awake()
{
_material = GetComponent<MeshRenderer>().material;
}
private void Update()
{
_value = Mathf.Clamp01(_isSeeing ? _value + speed * Time.deltaTime : _value - speed * Time.deltaTime * 5);
_material.SetFloat(Vector1Value, _value);
}
private void OnBecameVisible()
{
_isSeeing = true;
}
private void OnBecameInvisible()
{
_isSeeing = false;
}
}
在完成上面的效果之前,有一个先前的版本。是如下的形式,这样子的话消融的边太硬了。效果如下。
这个方法只是根据自己的猜想实现的一种方法,和《江南百景图》中的方法不一定相同。(话说我都做完了才发现,原来游戏中轮廓的线条明显比显示完成之后的线条要粗,也就是说显示完成之后轮廓应该是不在了的。估计是完整的图片并不是像我这里一样只有颜色,不过算了我也懒得改了,反正就是做着玩)
而且我这个将轮廓和颜色混合(当然用透明度做了一些插值,不是直接混合,因为直接加或乘都会让结果颜色改变),效果和直接渲染两个sprite重叠是不一样的。左为两个sprite,右为用我写的shader渲染。但是无伤大雅了吧。也许用多pass渲染会好些。
-- END --
公众号后台回复「资料」获取超多学习福利
>>> 点击进入技术讨论群 <<< ▽想深入了解么?
长按/扫码关注我吧↑↑↑
觉得不错就点个在看吧!