千家信息网

Unity3D中的水特现模拟雨天

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,这篇文章主要介绍"Unity3D中的水特现模拟雨天",在日常操作中,相信很多人在Unity3D中的水特现模拟雨天问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Unity
千家信息网最后更新 2026年11月04日Unity3D中的水特现模拟雨天

这篇文章主要介绍"Unity3D中的水特现模拟雨天",在日常操作中,相信很多人在Unity3D中的水特现模拟雨天问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Unity3D中的水特现模拟雨天"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

在写实类游戏制作时,常需要下雨场景的制作,由于日常生活中几乎所有物体都会被淋湿,所以下雨的制作其实需要考虑的方面有很多,我们将从粒子,材质,脚本控制等方面,分析一下应该如何渲染一个下雨的场景。

  1. 材质高光:

Unity的Standard Lighting中,使用GGX作为BRDF的高光算法,GGX具有拖尾感,可以较好的模拟潮湿物体表面的反光效果,首先我们来看一下这张故宫下雨时的照片(图侵删):

在普通游客的眼里,地面变得"湿滑"了,然而在渲染工程师的眼里,我们应该将这个"湿滑"的效果在PBR中分成四部分:Smoothness的提高,Specular Color的变亮以及GI Occlusion的降低和法线贴图比重的降低。首先,提高Smoothness是毫无疑问的,要让物体表面光滑首先要降低粗糙度,但是仅仅降低粗糙度是不行的,水停留在物体表面,这时反射光线的是水而不是物体本身,因此物体本身的漫反射会被降低,因此被淋水的物体看起来颜色会变深,根据物理反射定律,物体本身色彩无变化,即光线反射比例无变化的情况下,高光程度应提高,所以会表现出高光率提高的现象。同样,因为积水在物体表面的停留,物体受环境光影响会增大,这时我们应该适当降低Occlusion Map的影响,并降低法线贴图的偏移强度,这些在Unity的Standard Shader中都有提供,不需要手动写Shader,当然,如果要处理一个大场景,希望通过全局变量控制,还是应该手写shader进行精确优化的,因此,希望读者能够不依赖Shader Forge, Unity Surface Shader等辅助功能,独立编写基于PBR Shader。至于反射图像的处理,我们一般通过Reflection Probe, Screen Space Reflection & Planar Reflection等方法实现,这并不在本文讨论的范围内,我们将会在本专栏的其他文章中详细讨论。

不同反射率的材质

接下来就是雨水的制作了,雨水本身的粒子效果制作虽然属于比较初级的粒子制作,甚至Assets Store上也有大量的资源,但是对美术制作能力有比较高的要求。如果像我一样,美术功底奇差无比,完全可以直接买一个效果实现#手动斜眼#,然后在粒子发射器上绑定一个脚本,使其始终在摄像机上方悬停,可以看到在示例中,我们使用粒子碰撞防止穿帮:

在摄像机第一视角效果如下:

雨水落在平面

到此,一个简单的雨水渲染就出来了,然而,整个画面看起来僵硬死板,这是因为我们没有表现出雨滴打在地上的效果,因此,我们需要模拟一个动态的法线贴图,让地面的法线"动起来",解决的方法有许多,最简单的方法就是序列帧,在CG软件(如Houdini,Substance Painter等)中制作序列帧并且渲染,然后在Unity中播放,这当然是一种比较简单的方法,但是同样也无法实现真正的实时与随机,我们这里则是使用Unity自带的CommandBuffer进行比较底层的图形绘制,实现随机的雨点特效。

学习过渲染管线基础的朋友都知道,Unity的摄像机其实并不是绘制RenderTexture的唯一方法,它只是封装的比较上层的方法,其实摄像机的工作流程就是(剔除->绘制网格->后处理)这三部分,无论是Forward path或是Deferred Shading path,亦或是Unity 2018最新提供的HDRP和LWRP,本质上都是这三部,区别仅仅在于,deferred shading会将光照作为后处理运算,而forward path会直接将灯光信息传入shader中进行光影运算并直接输出色彩,而我们这里并不需要动态剔除,只需要使用command buffer在一个指定的Render Target上进行GPU Instance,使用指定的材质绘制大量面片即可。有朋友问我为何不使用Unity 2017推出的CustomRenderTexture进行绘制,我认为,CustomRenderTexture只是给不会渲染底层的程序提供的一个上层封装,实际功能不如使用Graphics类或CommandBuffer直接进行绘制,后者虽然门槛较高但是功能更加强大,大概相当于美图秀秀和PhotoShop的关系(只是个人看法,别怼别怼)。

首先我们需要手动生成一个正方形Mesh,并将indexBuffer设置为四边形绘制,实现非常简单,代码如下:

由于我们是直接往屏幕上绘制的,所以根本不需要考虑ViewProjectionMatrix的问题,直接用NDC坐标(-1, 1)进行绘制即可,如果直接将这个mesh绘制到RenderTarget上,就是一个覆盖全屏的Mesh。

接下来我们要让这个mesh缩小并且随机分布在RenderTarget上,实现雨滴随机散落的效果,这时候就需要使用矩阵进行变换了,然而,雨滴数量众多,在本例中我们绘制了1023个雨点,所以很难依靠CPU进行迭代绘制,无论是计算还是Drawcall,消耗都是难以接受的。所以我们使用Compute Shader与Gpu Instance进行绘制,大幅度提高运算效率。

首先是Compute Shader,这里不赘述如何使用Compute Shader,只是提供Compute Shader的实现目标与过程。实现目标:生成1023个随机分配位置的矩阵并执行1023个计时器。为何要用计时器呢,原因很简单,当一个雨点散落到地上时,涟漪应该是越来越浅直到消失的,在涟漪消失时更新位置信息,使面片在另一个位置绘制。实现代码如下:

这里来解释一下这段代码的意义,MatrixBuffer是我们需要使用的1023个坐标矩阵,而timeSliceBuffer则是我们需要使用的计时器,其中float2的x值是计时器数值而y值是计时器速度。_DeltaFlashSpeed则是由脚本传入的每帧的更新,即Time.DeltaTime * X; 然后是两个LocalRand函数,使用魔数运算输出一个伪随机数。其中第一个函数会输出一个(-1, 1)区间的float2随机数,用于随机生成一个平面位置,而第二个函数则会输出一个(0, 1)区间的float随机数,用于生成一个随机的计时器速度。

下面的CSMain函数就比较简单了,当计时器数值>1时,归0并重新生成随机的速度与位置。根据线代基础,矩阵的M03, M13决定了xy轴的位置,M00,M11则决定了xy轴的Scale,而这里为了偷懒,果断省略了雨滴大小的随机,直接用同样大小的面片。

在ComputeShader中运算完毕后,就可以在脚本里获取计算的结果,并且使用运算结果进行绘制了,当然,在此之前我们需要先进行初始化:

这里初始化了Compute Shader,Compute Buffer以及需要用到的GPU Instance材质与高斯模糊材质(之后会用到)。

接下来就是调用Compute Shader并使用CommandBuffer进行绘制:

首先,指定renderTarget并初始化为(0.5,0.5,1)也就是标准的法线贴图格式,然后使用Compute Shader输出的矩阵进行Gpu Instance,最后经过高斯高斯模糊,使画面顺滑一些。

有了输入的计时器与输入的矩阵,就可以开始绘制波纹了,波纹绘制实际非常简单,直接用Alpha Blend实现减弱效果,用三角函数实现波动即可,直接上代码:

Shader "Unlit/Wave"
{
SubShader
{
Tags { "RenderType"="Opaque" }
ZWrite Off
ZTest Always
Cull Off
Blend oneMinusSrcAlpha srcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
#pragma target 5.0
#define MAXCOUNT 1023
StructuredBuffer timeSliceBuffer;
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct v2f
{
float4 vertex : SV_POSITION;
float timeSlice : TEXCOORD0;
float2 uv : TEXCOORD1;
};

v2f vert(appdata v, uint instanceID : SV_InstanceID)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
o.vertex = mul(unity_ObjectToWorld, v.vertex);
o.timeSlice = timeSliceBuffer[instanceID].x;
o.uv = v.uv;
return o;
}
#define PI 18.84955592153876
float4 frag(v2f i) : SV_Target
{
float4 c = 1;
float2 dir = i.uv - 0.5;
float len = length(dir);
bool ignore = len > 0.5;
dir /= max(len, 1e-5);
c.xy = (dir * sin(-i.timeSlice * PI + len * 20)) * 0.5 + 0.5;
c.a = ignore ? 1 : i.timeSlice;
return c;
}
ENDCG
}
}
}

shader非常简单,只是绘制了一个大致效果,最后生成的法线贴图效果如下:

可以看到,这张对密集恐患者非常友好的图片,已经有了深浅不一的涟漪花纹(虽然比较难看),我们将这张renderTarget放到地面上,效果如下:

可以看到,地面已经有了法线的涟漪,最近放假回国探亲,只能用家里的古董笔记本写文章,不过从粒子到动图绘制,在这台古董上也只需要4ms左右的运算时间,drawcall也因为gpu instance的原因并没有额外增加,可以说性能表现比较令人满意。

到此,关于"Unity3D中的水特现模拟雨天"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

效果 物体 计时器 制作 方法 法线 位置 材质 矩阵 粒子 反射 生成 运算 函数 只是 就是 贴图 学习 输出 雨天 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网佳科技有限公司 科技股互联网 齐家互联网科技 百单互联网科技有限公司 互联网科技公司做什么 互联网科技有限公司 翻译 上海电发互联网科技有限公司 互联网软件和科技 互联网科技革命什么开始 华夏互联网科技业 中国互联网十大科技股排名 互联网金融科技展 高科技互联网发展前景如何 玉溪新华互联网科技好不好 长沙互联网科技 产业互联网科技服务公司 郑州欣桑互联网科技有限公司 广东鹅鹅鹅互联网科技有限公司 数字科技和互联网金融哪个好 互联网科技创业有什么好项目 互联网佳科技有限公司 高科技互联网 广西拼得多互联网科技有限公司 央行互联网金融科技公司 上海宁丞科技互联网 杭州壁岐互联网科技有限公司 互联网在线教育科技创业 上海钢联属于互联网科技股吗 浙南科技城互联网大厦招聘 美国五大互联网科技公司市值多少
0