Unity开源项目2D流体渲染实现分析
开源项目LiquidEffect渲染分析
- 项目传送门
- 实现流程
- 步骤一 创建刚体
- 步骤二 降采样与模糊处理
- 降采样分析
- C#部分
- 顶点着色器
- 片元着色器
- 分析
- 模糊分析
- 步骤三 Alpha过滤
项目传送门
GitHub地址
实现流程
一共三个步骤:
- 创建若干个圆形Sprite作为“液体粒子”,每个“粒子”都是一个Dynamic的RigidBody2D,并赋予合适的物理材质和2D Collider
- 利用Blur着色器将所有的液体粒子图像模糊化并渲染到一张RenderTexture上
- 将RenderTexture使用UnlitMod Shader(选择Alpha值在一定范围内的像素渲染成同一颜色)渲染到一个片儿上。
步骤一 创建刚体
作者用了一个比较讨巧的方式来模拟水,使用大量带物理属性的小球来模拟流体的流动,只要“粒子”足够多,足够小,就可以拟态流体
先看看他的场景里都有什么
- Scene节点下存放平台黑色阻挡物体
- Effect Camera为特效处理摄像机
- 设置了Culling Mask,只观察小球
- 设置了Target Texture,将渲染结果输出到一张RenderTexture
- MeshWithTextureFromCamera节点为Effect Camera渲染的RT输出
- MainCamera为主摄像机
- 设置了Culling Mask,观察阻挡物和MeshWithTextureFromCamera
- Particles Batch节点下是图中拟态用的蓝色小球,调整好合适的物理属性,摩擦力和弹性如下图:
步骤二 降采样与模糊处理
首先排除其他观测障碍,关掉EffectCamera的HDR和抗锯齿,以便观察结果
先看OnRenderImage做了什么,上代码
// Called by the camera to apply the image effect
void OnRenderImage(RenderTexture source, RenderTexture destination)
{int rtW = source.width / 4;int rtH = source.height / 4;RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);// Copy source to the 4x4 smaller texture.DownSample4x(source, buffer);// Blur the small texturefor (int i = 0; i < iterations; i++){RenderTexture buffer2 = RenderTexture.GetTemporary(rtW, rtH, 0);FourTapCone(buffer, buffer2, i);RenderTexture.ReleaseTemporary(buffer);buffer = buffer2;}Graphics.Blit(buffer, destination);RenderTexture.ReleaseTemporary(buffer);
}
整体模糊处理一共三步
- 把本摄像机渲染的source数据降采样到四分之一
- 对降采样后对结果进行几次模糊迭代
- 把模糊处理的结果输出到destination,也就是屏幕
先看结果再看分析,打开FrameDebug窗口,点击播放,点到这个位置,如下图:
我的iterations迭代次数赋值为7,Draw GL数量为8,是因为第一个为DownSample4x(source, buffer)
降采样操作,依次点击Draw GL会发现图片越来越模糊,如下图:
降采样分析
因为作者写法很的很有歧义,很不好懂,这里详细解释一下
C#部分
上代码,先是C#部分
// Downsamples the texture to a quarter resolution.
private void DownSample4x(RenderTexture source, RenderTexture dest)
{float off = 1.0f;Graphics.BlitMultiTap(source, dest, material,new Vector2(-off, -off),new Vector2(-off, off),new Vector2(off, off),new Vector2(off, -off));
}
Graphics.BlitMultiTap函数
- 第一个参数source为2048x2048尺寸的RenderTexture
- 第二个参数dest为1/4尺寸的512x512的RenderTexture
- 第三个参数是可变Vec2数组,官方解释是偏移了多少像素的UV坐标,并且依次填充到Quad方块的纹理单元中
Each vertex of the quad has multiple texture coordinates set up, offset by offsets pixels.
顶点着色器
然后是shader部分,原作者是这么写的
structv2f {float4 pos : SV_POSITION;half2 uv : TEXCOORD0;half2 taps[4] : TEXCOORD1;
};
//顶点着色器
v2f vert( appdata_img v ) {v2f o; o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord - _BlurOffsets.xy * _MainTex_TexelSize.xy;o.taps[0] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy;o.taps[1] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy;o.taps[2] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);o.taps[3] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);return o;
}
- _MainTex_TexelSize为Unity默认赋值,其为
Vector4(1 / width, 1 / height, width, height)
- _BlurOffsets为Unity的黑魔法,默认赋值为
Graphics.BlitMultiTap
函数的Vector2[] offsets
的第一个值 - 顶点着色器里的_MainTex_TexelSize * _BlurOffsets.xy这个函数,Unity做了转化,实际为_MainTex_TexelSize.xy * _BlurOffsets.xy
模糊处理是采用的均值模糊,一个像素的颜色为上下左右的颜色平均值,中心像素为目标像素,他的值是周围四个格子颜色的平均数
顶点着色器他就是想取到像素周围四个顶点的纹理坐标,这里看到作者只用了offset的第一个值,其他传入的参数并没有用到,估计也是参考的,所以我改了一下代码,让参数利用率高一些,如下:
v2f vert( appdata_full v ) {v2f o; o.pos = UnityObjectToClipPos(v.vertex);o.taps[0] = v.texcoord;o.taps[1] = v.texcoord1;o.taps[2] = v.texcoord2;o.taps[3] = v.texcoord3;return o;
}
改了顶点输入结构appdata_full
为Unity内置结构,贴出来给大家参考,如下,因为之前传入了四个偏移量,并且已经依次填入顶点数据并且已经算好偏移uv,所以直接赋值就好。(因为顶点到片元数据为差值计算,可以直接赋值在顶点数据里)
struct appdata_full
{float4 vertex : POSITION;float4 tangent : TANGENT;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;float4 texcoord1 : TEXCOORD1;float4 texcoord2 : TEXCOORD2;float4 texcoord3 : TEXCOORD3;
#if defined(SHADER_API_XBOX360)half4 texcoord4 : TEXCOORD4;half4 texcoord5 : TEXCOORD5;
#endiffixed4 color : COLOR;
};
片元着色器
//片元着色器
half4 frag(v2f i) : SV_Target {half4 color = tex2D(_MainTex, i.taps[0]);color += tex2D(_MainTex, i.taps[1]);color += tex2D(_MainTex, i.taps[2]);color += tex2D(_MainTex, i.taps[3]);return color * 0.25;
}
- _MainTex为传入source图像
这个很好理解,算好周围颜色加起来做平均数
分析
输入为2048 * 2048的全屏RenderTexture,然后创建一个1/4大小的Rt buffer,实际就是创建一个1/4 Rt四边形,在片元着色器采样_MainTex,采样到四边形,则为GPU里的RT buffer镜像,存入真实采样color结果,根据选择的Rt格式为准(譬如float浮点数),此时这个Rt buffer为512 * 512,完成降采样
模糊分析
上代码
// Performs one blur iteration.
public void FourTapCone(RenderTexture source, RenderTexture dest, int iteration)
{float off = 0.5f + iteration * blurSpread;Graphics.BlitMultiTap(source, dest, material,new Vector2(-off, -off),new Vector2(-off, off),new Vector2(off, off),new Vector2(off, -off));
}
这里使用的shader和降采样使用的是同一shader,所以算纹理坐标是一样的,只不过是改了offsets的偏移值,之前降采样是取上下左右四个值,现在是根据模糊迭代次数取不同偏移量的值,offsets随着迭代次数递增,取越远的位置颜色,blurSpread为预先定义好的模糊系数,可以尝试调整观察结果。执行7次模糊结果如下图,然后将此模糊图像渲染到摄像机目标RT(2048x2048),这时如果设置纹理采样模式为双线性差值采样,模糊效果会更进一步。而且适当的降采样也会对模糊有帮助。
步骤三 Alpha过滤
这步骤思路很简单,就是把上面模糊处理的图像,把模糊的颜色也涂成纯色,这样就把小球周围扩大的模糊颜色链接起来,就变成了水。
- MeshWithTextureFromCamera为一个Quad方块,使用的材质贴图为刚才的RT
- 通过shader将Quad渲染出来
上代码,主要看片元着色器
fixed4 frag (v2f i) : SV_Target
{// sample the texturefixed4 col = tex2D(_MainTex, i.texcoord);clip(col.a - _Cutoff);if(col.a < _Stroke) col = _StrokeColor;else col = _Color;return col;
}
操作非常简单,因为模糊处理后,小球中央不透明度最大,随着发散越边缘部分模糊越大,不透明度也越小,所以就可以通过Alpha进行过滤判断
- clip(col.a - _Cutoff); 将特别微弱的颜色剔除掉
- if(col.a < _Stroke) col = _StrokeColor; 将剔除后的最边缘部分显示为一个指定颜色
- else col = _Color; 将剩余部分填充指定颜色
最后,让我们看一个有描边的黄色液体,嘿嘿
Unity开源项目2D流体渲染实现分析相关推荐
- 【Unity开源项目精选】ML-Agents:给你的游戏加入AI
洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. 今天给你分享一个Unity开源项目,希望对你有帮助哦! ML-Agents Unity机器学习代理工具包(ML-Agents) ...
- 【开源项目----Android OPenGLES渲染YUV视频文件】
[开源项目----Android OPenGLES渲染YUV视频文件] OpenGLES对YUV渲染相关文章参考
- 【Unity开源项目精选】UniRx:Unity中的响应式编程
洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. 本篇文章首发于我的公众号:洪流学堂 今天给你分享一个Unity开源项目,我们一起来看看吧! UniRx是什么? UniRx ( ...
- 【Unity开源项目精选】Entitas:Unity DOTS的先行者
洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. Entitas Entitas是Unity官方推出DOTS之前的一个开源ECS框架.不过自从Unity官方启动DOTS以来,E ...
- 【Unity开源项目精选】Unity引擎源码的C#部分
洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. 今天给你分享一个Unity开源项目,我们一起来看看吧! Unity引擎源码的C#部分 Unity 引擎和编辑器源代码的 C# ...
- 【Unity开源项目精选】xLua:Unity热更新首选
洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. 今天给你分享一个Unity开源项目,我们一起来看看吧! xLua C#下Lua编程支持: xLua为Unity. .Net. ...
- 【Unity开源项目精选】AssetStudio:提取Unity游戏的资源
洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. 今天给你分享一个Unity开源项目,我们一起来看看吧! AssetStudio AssetStudio 是一个用于探索.提取和 ...
- 【Unity开源项目精选】AirSim
洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. 今天给你分享一个Unity开源项目,希望对你有帮助哦! AirSim AirSim由微软AI研究部门的团队开发,它是一个用于自 ...
- Github上有什么好的unity开源项目?
程序员宝藏库:https://gitee.com/sharetech_lee/CS-Books-Store 直接在GitHub搜关键词「Unity」会返回将近30万个结果,即便是把范围限定在Unity ...
最新文章
- Java实用教程笔记 输入、输出流
- LINUX符号、快捷键、正则
- 【转】[你必须知道的.NET]第二十一回:认识全面的null
- halcon11用于C++的HTuple.h头文件,纯手添中文翻译!
- Quality Center Issue with CAPICOM.DLL not prop...
- field property data type validation error in metadata
- 房价必须涨,不涨不正常!因为妈妈又印钱了
- Uber无人车事故又有新内情曝光:为竞争盲目冒进,瘾大技术差
- c语言qq聊天刷屏代码大全,QQ聊天刷屏脚本 达人分享技巧
- 自建rtmp直播和朋友一起异地看电影
- Java面试面经大合集(含答案),大厂越来越简单进了,
- 什么是计算机剪贴板介绍,剪贴板在哪里,详细教您如何打开电脑剪贴板
- 开机黑屏、自检不通过,主板检测卡代码为25问题解决
- XP操作系统安装的硬盘空间要求
- VMware虚拟机屏幕大小(屏幕分辨率)调整
- 点阵图(位图)与矢量图的区别
- 立足中国、跻身全球头部代工厂行列,华虹加速蜕变升级
- Python 数据分析微专业课程--项目06 城市餐饮店铺选址分析
- python安装xgboost的方法
- 玉雕工作室php,吴春强玉雕大师—吴春强玉雕工作室