整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

在手机游戏中实现下雨系统

者:日音

先展示最终效果:

http://v.qq.com/x/page/j0808yxmm3w.html

雨水会导致物体潮湿,会在平面形成水波,会在斜面形成纹路。雨会被物体阻挡,阻挡的部分依然保持干燥,干燥和潮湿有过度。水积累到一定程度还会有反射。

很早就想做一个完整的天气系统。不过难度太大了,所以打算拆分成一个个小系统。首先就是做最常见的下雨。

雨水本身实现已经有很多成熟的方式,包括我个人最喜欢的angrybots里面的雨,性能和表现都非常好。遗憾的是不够通用,所以我打算还是重新做一个分离的雨滴,方便后面加入一些中级效果,例如遮挡之类这样的特性。

我假定雨是有一个下界的,毕竟如果你潜入了水底,那么肯定就不希望会有任何下雨被看到。上界就不需要了,如果你高到一定程度,发现只有下方有雨,那估计也非常奇怪。

我们需要设计一种tile方式的雨来处理摄像机看到雨的范围。水平方向上可以调整tile个数,垂直方向我可以根据控制雨下落的生命周期来控制。

根据这张图,我们要计算出摄像机能看到的AABB盒,从而去做需要雨落下的物体的范围。

因为每个雨滴都是独立的,这次我们可以放心使用广告牌技术了。

另外,由于雨离摄像机太近会有点太大块的感觉,所以我建议将摄像机的nearPlane调整到1左右。

由于是局部雨,摄像机快速移动或者瞬间切换位置的时候,需要还原雨本应该的场景。 我们保存上一帧的AABB盒,并且对当前的AABB盒遍历,判断如果在原来的AABB盒内,那么就啥都不做,否则需要还原雨滴。

经过测试,发现虽然有一点点的衔接不够流畅的问题,但整体感受其实还不错。

不过上面做出的雨太干巴巴了,首先我要考虑的是增加雨滴打中地面的波纹。

波纹我们参考的是这篇文章:

https://seblagarde.wordpress.com/2013/01/03/water-drop-2b-dynamic-rain-and-its-effects/

其中涉及波纹的部分比较简单。

r通道代表离圆心的距离。gb通道代表法线方向,a通道代表随机强度值。

这样之后,波纹是有了。

远处可以优化下,太远的地方其实可以不用算,优化性能。然而这还不够,因为这地面看上去压根就不像湿滑的,湿滑的地面需要额外处理一下。通过增加一张法线贴图,控制一下uv的扰动,并且替换了下地表,来展示雨水的效果。

静态图效果不明显,还是看视频吧。

接下来要处理的是水导致物体本身的变化。一般颜色会稍变深,表面会变光滑,如果有水坑的话就会反光之类。其实就是pbr里面的smooth。但是手机用全套pbr性能有点耗,打算先把brdf3的一部分拿过来用。

做了一些修改。然后就是要考虑被阻挡的部分,我打算在顶部放一个摄像机,用来记录物体的深度,然后整个系统都需要去判断深度,然后看是否被雨水阻挡,再做相应处理。实际操作分为这么几步:

1.顶部摄像机用深度shader替换去渲染物体,然后做一下高斯模糊,用来让边界过度的更加自然。

2.平面shader把世界坐标转到顶部摄像机裁剪空间坐标,算出uv去取深度值,然后根据矩阵反算出世界坐标的值,比较两个世界坐标的y,来看是否顶部有物体挡住,如果有的话,就对潮湿效果,反射效果,波纹效果进行弱化处理。

3.反射效果就是用水面反射,增加一个反射摄像机,具体可以参考自带的水面反射。

效果大概是这样:

看视频效果更好一些。

手机上试了一下,效果全开的话帧率下降的比较厉害,然后去掉了反射效果,简化了光照模型之后,帧率得到了改善。

说下这个雨的注意事项。

我的本意是希望可以在不更改项目的情况下增加这个雨的效果,但我发现这样是需要做屏幕后处理才可以达到,但处理起来比较复杂。最终我还是选择了用Plane,Cube来做效果。如果要整合到自己的项目中,还是需要做一些代码上的整合。例如水导致物体潮湿,可以把我的函数和贴图放到自己的shader中,也可以直接修改shader里面的高光,光滑度等这些参数。

对于遮挡摄像机的部分,需要设置合适的大小和位置,如果场景特别大的话,通过移动摄像机的话,边缘部分会产生抖动。所以我建议大场景要使用多个深度摄像机或者自己提前烘焙好深度数据(如果场景没有动态障碍物的话)。

联系我们

欢迎优质创意项目随时与我们联系:

Danielkyan@tencent.com

Yunmi@tencent.com

在玩 HDRP 的内置 Lit 着色器的时候,对它的 Mask Map 贴图很感兴趣,感觉似乎能够为材质添加很多细节

不使用 Mask Map

使用 Mask Map

查了下文档,发现 Mask Map 是分 RGBA 通道作为灰度蒙版,为材质添加金属度、环境光遮蔽、细节贴图蒙版与粗糙度效果的:

让我最感兴趣的是 A 通道的粗糙度蒙版,就像上图那样,能营造出非常类似物体表面的水雾的感觉。

恩..如果我用 Shader 让这个 A 通道做一个平移,再加点噪声,说不定就能做出来类似下雨时物体表面潺潺流水的效果?

实现思路

使用 ShaderGraph 的 TimeTilling and Offset节点将 UV 做一个平移,加上线性噪声节点做一些扭曲,添加一点随机性。最后直接复用原材质的 Mask Map 的 A 通道并应用扰动。用一个布尔来控制是否应用效果。添加各种属性值就不说了。应该还不错。

在实现过程中,由于 HDRP 的内置 Lit 着色器没有 ShaderGraph 版本,就从论坛上找了一个官方的 Lit 着色器的 ShaderGraph 版本,基于它进行修改。

整体(糊也没事..大部分是官方给的,用于实现 Lit 的特性,核心就那上面的一小点)

核心效果实现(就这几个节点..真的挺简陋的..)

效果

砖墙材质

石碑(?) 材质

模型效果

一些个人感受:

  • 这是个很粗糙的效果,用到的节点也很少,之后要实际应用的话肯定要补充很多细节,比如单独做水流的 Mask 应该会好很多

  • 个人认为的效果优缺点:

    • 优点:

      • 和网上其他的雨水效果比起来,对性能影响应该蛮低的。加上天气效果以及一些点缀应该也能实现不错的效果

      • 简单啊(连我都能做出来..),直接复用材质自己的 Mask Map 也懒省事了

      • 因为不同材质的 Mask Map 不同,所以这个效果也会带有各自材质的特点,不会说效果千篇一律看着疲劳

    • 缺点:

      • 对于较为光滑的平面类物体感觉效果比较一般

      • 因为复用了原材质的 Mask Map,应用效果时材质自身的粗糙度会丢失,不太好

      • 可远观而不可亵玩(bushi),在远处看起来还不错,如果离得太近的话就能比较明显的看出来违和的平移与噪声

  • 总之还是个很粗糙的效果,不过这种思路应该还是有点意思的,必能活用于下一次..

参考链接

  • https://forum.unity.com/threads/trying-to-replicate-the-hdrp-lit-shader-i-need-help-with-the-detail-input-part.660538/Unity Forum-ShaderGraph 版 Lit 原贴

  • https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@7.1/manual/Mask-Map-and-Detail-Map.htmlMask Map 文档

  • https://github.com/OnyxAmber/UnityHDRP_ShaderGraphTest把着色器图与材质传到 Github 上了,项目太大就不传了,直接拖入 Unity 窗口即可。使用贴图也是 HDRP 自带的示例。

通过阅读这篇文章,你将学会用Python创建一个天气警报系统,当它预测未来几小时内天空将下雨/下雪时,它会向多个收件人发送一封电子邮件通知。电子邮件通知包含其他信息,如预测的温度和湿度。

本教程有3个部分:

1.设置

2.实现

3.结果


设置

天气API

我们将使用ClimaCell的天气API来获取预报天气数据。根据您的需要,它提供了相当多的有用和准确的数据。

它涵盖了4周以前的历史站点数据以及15天以前的每日预报数据。此外,你可以很容易地实现它的官方文件提供参考4种不同的计算机语言:

  • JavaScript
  • Ruby
  • Node
  • Python

前往注册和注册一个新帐户。一旦完成,您应该会看到下面的指示板,它概述了计划细节和您的调用活动。



请注意API键,因为我们将在后面的代码中使用它。


邮件配置

我将使用个人Gmail账号通过SMTP给自己发邮件。为了使用它,你需要改变帐户设置的配置,并打开不太安全的应用程序访问。

转到帐户设置,然后点击安全菜单。


打开不太安全的应用访问,如下所示

完成之后,在项目的根目录中创建一个名为config.ini的新文件。它将被用作我们项目的配置文件。将以下代码添加到其中。

[email]
email=your_email@gmail.com
host=smtp.gmail.com
port=587
password=your_password
  • 电子邮件-您的电子邮件帐户的名称
  • 主机- smtp服务器的主机名。修改这个基于smtp服务器为您的电子邮件
  • 端口-用于smtp服务器的端口。修改这个基于smtp服务器为您的电子邮件
  • 密码-密码到您的电子邮件帐户。请务必不要将此文件或信息泄露给其他人。


Python模块

强烈建议为这个项目创建一个虚拟环境。在终端中运行以下命令来安装configparser模块。它在从文件加载配置设置时非常有用。

pip install configparser


实现

在与config.ini相同的目录中创建一个名为weather_email.py的新文件。这个文件作为我们的应用程序的电子邮件模块。

import

在文件的顶部添加以下导入声明

try:
    import configparser
except:
    from six.moves import configparserimport smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import requests

接下来,创建一个字典,表示在下雨或下雪时我们将要发送的消息。您可以根据您的用例创建自己的映射或自定义消息。

weather_dict = {'freezing_rain_heavy': 'Heavy rain and snow', 'freezing_rain': 'Rain and snow', 'freezing_rain_light': 'Light rain and snow', 'freezing_drizzle': 'Light drizzle and snow', 'ice_pellets_heavy': 'Heavy ice pellets', 'ice_pellets': 'Normal ice pellets', 'ice_pellets_light': 'Light ice pellets', 'snow_heavy': 'Heavy snow', 'snow': 'Normal snow', 'snow_light': 'Light snow', 'tstorm': 'Thunder storm', 'rain_heavy': 'Heavy rain', 'rain': 'Normal rain', 'rain_light': 'Light rain'}


天气API设置

初始化调用weather API时需要的以下变量。

url = "https://api.climacell.co/v3/weather/nowcast"
querystring = {"lat":"1.29027","lon":"103.851959","unit_system":
               "si","timestep":"60","start_time":"now","fields":"temp,humidity,weather_code",
               "apikey":"xxxx"}

我们将调用nowcast API,它有以下参数,可以修改:

  • 纬度,-87至89
  • 经度,-180到180度
  • unit_system—单位制,“si”或“us”
  • 时间步长-时间步长,分1到60。将start_time设置为现在并将timestep设置为60将返回7个数据点。(现在,60分钟后,120分钟后,……)
  • start_time—您可以设置自己的时间,或者现在就初始化它
  • end_time—限制结束时间的可选参数。默认情况下,它将返回距离当前时间戳最多6小时的数据。
  • 字段-从所提供的数据层中选择的字段(如“降水”或“阵风”)。我在本教程中使用了temp,湿度和weather_code。
  • apikey -来自Climacell天气API仪表板的API键


邮件发送

我们将创建一个名为EmailSender的新类,并像下面这样初始化它。我们使用configparser模块从config.ini中读取数据,并将其分配给相应的变量。

def __init__(self):
    self.cf = configparser.ConfigParser()
    self.cf.read('./config.ini')
    self.sec = 'email'
    self.email = self.cf.get(self.sec, 'email')
    self.host = self.cf.get(self.sec, 'host')
    self.port = self.cf.get(self.sec, 'port')
    self.password = self.cf.get(self.sec, 'password')

在类内部创建另一个函数SendEmail,它接受一个接收者参数。它接受列表而不是字符串。这允许我们向多个电子邮件地址发送相同的电子邮件通知。

def SendEmail(self, recipient):

在函数内部,使用以下代码初始化一个新的MIMEMultipart对象

title = "Home Sweet Home"msg = MIMEMultipart()
msg['Subject'] = '[Weather Notification]'
msg['From'] = self.email
msg['To'] = ', '.join(recipient)

调用天气API

下一步是通过请求模块调用API,它将以json的形式返回结果。

response = requests.request("GET", url, params=querystring)
result = ""json_data = response.json()

您可以充分利用结果并将其映射到我们在上面指定的字典,以便创建所需的通知消息。然后,用它初始化一个MIMEText对象,并将其附加到MIMEMultipart对象。通过调用smtplib结束它。SMTP上下文管理器发送电子邮件。

msgText = MIMEText('<b>%s</b><p>%s</p>' % (title, result), 'html')
msg.attach(msgText)with smtplib.SMTP(self.host, self.port) as smtpObj:
    smtpObj.ehlo()
    smtpObj.starttls()
    smtpObj.login(self.email, self.password)
    smtpObj.sendmail(self.email, recipient, msg.as_string())

查看以下网址以获得完整的代码:

https://gist.github.com/wfng92/f5af6144053aeab514e5ff330949b112

您的根目录中应该有以下文件。

  • config.ini
  • weather_email.py

只要这两个文件与您调用的Python文件位于同一目录中,您就可以在任何Python应用程序中轻松触发电子邮件警报功能。只需根据您的用例修改import语句。下面的示例概述了在未来6小时内下雨或下雪时向两个收件人发送电子邮件通知的代码。

import weather_emailemail_obj = weather_email.EmailSender()
email_obj.SendEmail(["email@gmail.com", "email2@gmail.com"])


结果

让我们看一下运行测试时的结果。我接到通知,说我家下着小雨。

当雨停的时候,我运行了相同的代码,预报说6小时后还会下雨。也许我应该在下雨之前回去把我所有的衣服从晾衣架上取下来。

英文原文链接:

https://towardsdatascience.com/how-to-create-a-weather-alert-system-in-python-5fab4b42e49a