在Unity中实现基于粒子的水模拟(三:混合屏幕)
在Unity中实现基于粒子的水模拟(三:混合屏幕)
文章目录
- 在Unity中实现基于粒子的水模拟(三:混合屏幕)
- 前言
- 一、着色算法介绍
- 1.折射
- 2.反射
- 二、准备纹理
- 1.获取纹理
- 2.模糊纹理
- 2.混合主纹理上
- 总结
- 1.现有问题
前言
经过了前面的纹理,我们就到了最后的混合到屏幕阶段了,这个阶段的逻辑不是很难,本来是要基于这篇文章的公式来往上套的,不过由于本人水平问题并没有看懂作者的具体含义,于是就大概的实现了一下,估计出入挺大的。
效果看图:
项目链接:注意是在其中的master分支中
一、着色算法介绍
我们将颜色分为两部分,也就是折射和反射。
1.折射
折射要有最好的效果应该是要根据当前像素执行SSR算法,也就是计算出折射法线后,在通过深度重建的世界坐标中,用最接近折射位置的那个像素的颜色值作为折射的颜色值,但是这种方式太昂贵,所以没有采用这种方式。
本文用的方式是最简单的折射采样方式,根据法线以及液体宽度指进行uv偏移来获取折射的颜色值(因为实在看不懂作者到底什么意思,所以就这样简单实现了 )。
2.反射
反射的计算比较简单,直接传递一个Cube贴图,然后根据反射方向进行纹理采样即可。
最后将两个颜色根据透光度进行混合就计算完成了。
二、准备纹理
1.获取纹理
在SRP中可以通过设置CommandBuffer的SetRenderTarget将宽度、法线、深度图专门用特定的ShaderTagId指定,这样可以渲染两次就得到所有3张纹理,因为法线可以和深度一次得到。
但是在Build-in中我没有找到指定深度图的方法,导致后面模糊时不能很好的将深度值提取出来模糊,不过因为我们这个计算方式只使用了xy的法线值,可以将深度值存储在法线纹理的b通道中。
裁剪空间获取深度的公式:
其中f是远裁剪面、n是近裁剪面、z是视角空间z值。
代码表示:
//获取深度的公式,这个深度值就是深度图中的深度值
//_ProjectionParams是Unity提供的数据,y是摄像机的近平面、z是远平面
//i.pos是裁剪空间坐标,其中的w值存储着视角空间的z值
depth = (_ProjectionParams.z * i.pos.w - _ProjectionParams.z * _ProjectionParams.y)/((_ProjectionParams.z - _ProjectionParams.y) * i.pos.w)
//Unity会将深度图值转化,让近平面的精度更高,远平面精度可以低一点,
//因为浮点数在接近0时精度会上升
depth = 1- depth;
2.模糊纹理
模糊纹理使用的算法是双边滤波,这个算法可以让球体的边界混合起来,同时不会像高斯模糊一样让颜色值与周围混合,导致颜色不能准确对应该像素。
核心代码:
float CompareColor(float4 col1, float4 col2)
{float l1 = LinearRgbToLuminance(col1.rgb);float l2 = LinearRgbToLuminance(col2.rgb);return smoothstep(_BilaterFilterFactor, 1.0, 1.0 - abs(l1 - l2));
}float4 BilateralFilterFragment (Varyings input) : SV_TARGET{float2 delta = _PostFxEffectSource_TexelSize.xy * _BlurRadius.xy;//采集Normal的颜色值float4 col = SAMPLE_TEXTURE2D(_PostFxEffectSource, sampler_linear_clamp, input.screenUV);float4 col0a = SAMPLE_TEXTURE2D(_PostFxEffectSource, sampler_linear_clamp, input.screenUV - delta);float4 col0b = SAMPLE_TEXTURE2D(_PostFxEffectSource, sampler_linear_clamp, input.screenUV + delta);float4 col1a = SAMPLE_TEXTURE2D(_PostFxEffectSource, sampler_linear_clamp, input.screenUV - 2.0 * delta);float4 col1b = SAMPLE_TEXTURE2D(_PostFxEffectSource, sampler_linear_clamp, input.screenUV + 2.0 * delta);float4 col2a = SAMPLE_TEXTURE2D(_PostFxEffectSource, sampler_linear_clamp, input.screenUV - 3.0 * delta);float4 col2b = SAMPLE_TEXTURE2D(_PostFxEffectSource, sampler_linear_clamp, input.screenUV + 3.0 * delta);float w = 0.37004405286;float w0a = CompareColor(col, col0a) * 0.31718061674;float w0b = CompareColor(col, col0b) * 0.31718061674;float w1a = CompareColor(col, col1a) * 0.19823788546;float w1b = CompareColor(col, col1b) * 0.19823788546;float w2a = CompareColor(col, col2a) * 0.11453744493;float w2b = CompareColor(col, col2b) * 0.11453744493;float3 result;result = w * col.rgb;result += w0a * col0a.rgb;result += w0b * col0b.rgb;result += w1a * col1a.rgb;result += w1b * col1b.rgb;result += w2a * col2a.rgb;result += w2b * col2b.rgb;result /= w + w0a + w0b + w1a + w1b + w2a + w2b;return float4(result, 1);
}
双边滤波也需要像高斯模糊一样执行两次,对垂直以及水平进行模糊,具体实现可以参考这篇文章。
2.混合主纹理上
这部分就和正常的后处理流程一样了,具体后处理如何实现就不赘述了,这里只描写着色的核心代码。
首先第一步,进行深度对比,判断该像素是否需要进行液体着色,也就是是否被遮挡。
if(currentDepth >= waterDepth)return float4(currentColor, 1); //返回原本像素颜色
获得折射以及反射的颜色值:
float3 viewDirection = normalize( _WorldSpaceCameraPos - worldPos );float3 reflectDir = normalize(-viewDirection + 2 * waterNormal); //反射方向//反射颜色float3 specular = SAMPLE_TEXTURECUBE_LOD( _WaterReflectCube, sampler_WaterReflectCube, reflectDir, 0 ).rgb;float2 ofssetUV = (-viewDirection - 0.2 * waterNormal).xy * waterWidth * 0.2 + input.screenUV;//折射颜色float3 refrColor = SAMPLE_TEXTURE2D_LOD(_PostFxEffectSource, sampler_linear_clamp, ofssetUV, 0).rgb;//混合液体颜色,transLight是透光度refrColor = lerp(refrColor * _WaterColor.rgb, refrColor, transLight);
按照大佬文章的公式:
其中R1和R2分别是水和空气的折射率。
代码:
float n_0 = pow( (_WaterData.y - _WaterData.x) / (_WaterData.y + _WaterData.x), 2 );float fresnel = ( n_0 + (1 - n_0) * pow( 1 - dot(viewDirection, waterNormal), 5 ) )* waterWidth;float3 finalCol = refrColor * (1 - fresnel) + fresnel * specular;
总结
导致这个粒子水系列就正式完成了,我觉得这个实现的水不适合作为“水”,不过如果拿来做流体模拟的话还是可以的,因为有深度、法线图,用来实现牛奶等BSDF等渲染效果是很不错的,毕竟BSDF的一个难点是宽度计算,有了宽度其他计算就和BRDF没什么区别了。
1.现有问题
目前本场景的粒子并没有进行软粒子处理,如果有必要的话可以在渲染宽度时将深度图传入,在深度相近时进行透明,而且可以根据深度值进行Hi-z剔除,优化效果。
本项目的根据都是基于Unity的物理检测的,这个部分是损耗最大的部分,也是最容易出bug的部分,如果之后场景需要的话建议直接设置固定的流动方向,不进行真正的时时物理检测,刷新流动方向,这样CPU占用太大了。
理论上这些粒子着色都是要用ComputeShader写的,但是我在写这个系列时还不懂这些,在最近研究SRP时才知道有这个东西。
不过由于模拟时数据量太大了,这种直接将数据传递到顶点的方式说不定更适合物理模拟,不过之前实现的粒子系统可能就真的需要更新了,之后应该会更新Compute Shader进行剔除的粒子系统,更加全面的实现Unity新版粒子系统。
在Unity中实现基于粒子的水模拟(三:混合屏幕)相关推荐
- 在Unity中实现基于粒子的水模拟(二:开始着色)
在Unity中实现基于粒子的水模拟(二:开始着色) 文章目录 在Unity中实现基于粒子的水模拟(二:开始着色) 前言 一.生成顶点 二.偏移模拟 1.接收细分着色器输出的顶点 2.根据数据调用对应的 ...
- 在Unity中实现基于粒子的水模拟
曲面细分进行水模拟(一:物理模拟) 文章目录 曲面细分进行水模拟(一:物理模拟) 前言 一.曲线模拟的原理介绍 二.代码计算终点 1.代码原理介绍 2.第一条射线计算 3.第二条射线计算 4. 分配数 ...
- 在Unity中创建基于Node节点的编辑器 (二) 窗口序列化
孙广东 2018.5.13 csdn 的产品 , 真垃圾, 不想吐槽了, 文章保存就丢! 没办法 . 怎么不满意, 还是得继续用, 哎~~~ 第二部分 在Unity中序列化基于节点的 ...
- 在Unity中创建基于Node节点的编辑器 (一)
孙广东 2018.5.13 Unity AssetStore中关于Node节点 编辑器相关的插件可是数不胜数, 状态机,行为树,Shader 可视化等等. Unity自己也有 Animator的 ...
- 学习在Unity中创建一个动作RPG游戏
游戏开发变得简单.使用Unity学习C#并创建您自己的动作角色扮演游戏! 你会学到什么 学习C#,一种现代通用的编程语言. 了解Unity中2D发展的能力. 发展强大的和可移植的解决问题的技能. 了解 ...
- 【Unity学习笔记】Unity中的欧拉角(Euler Angle)和万向节(Gimbal)
声明:此篇文章是个人学习笔记,并非教程,所以内容可能不够严谨.可作参考,但不保证绝对正确.如果你发现我的文章有什么错误,非常欢迎指正,谢谢哦. 目录 1 奇怪的现象 1.2现象一 1.2 现象二 1. ...
- Unity中的灯光和渲染
一:Unity中的灯光 --Directional Light:模拟太阳光.它与位置无关,是平行光,可以调整旋转角度模拟昼夜 --Spot Light:模拟车灯.手电筒的光.舞台灯光 --Point ...
- 【Unity3D Shader编程】之五 圣诞夜篇 Unity中Shader的三种形态对比 混合操作合辑
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...
- Unity 中的声音系统
Unity 支持的音频格式 AIFF 最适合短音效果 可以在编辑器中按需求压缩 WAV 最适合短音效果 可以在编辑器中按需求压缩 MP3 最适合较长的音乐曲目 OGG 压缩音频格式(与iPhone设备 ...
最新文章
- python笔记6 模块与包 程序开发规范 包 re sys time os模块
- 译者招募 | 这本“顶级”微积分教材,中文版要来了!
- 连接阿里云和容器技术生态 - 阿里云开源容器项目汇总
- python安装后无法运行任何软件_为啥我按照python安装教程,总说无法启动此程序,因为计算机中丢失?...
- CVE-2012-4792Microsoft Internet Explorer 释放后使用漏洞
- 系统设计(二)——TinyURL系统设计
- (day 37 - 动态规划)剑指 Offer 46. 把数字翻译成字符串
- kubernetes Pod yaml解析注释
- mysql集群脑裂问题_redis集群怎么解决脑裂问题
- java编程新手初学者入门学习,看什么书比较好
- matlab 非线性辨识,非线性系统辨识Matlab实现
- 【人工智能】180页PPT,讲解人工智能技术与产业发展
- Python基础_闭包和迭代器
- 【人脸识别项目一】:眨眼检测
- Hypervisor介绍
- XXE漏洞(XML外部实体注入)
- CentOS 7 从本地 ISO 映像文件安装 Gnome GUI
- 用计算机可以干嘛的,计算机还可以做什么?
- Tsar学习笔记---tsar tsar2db mysql 集成调测篇
- 百度ECharts地图GeoJson数据在线下载 2021
热门文章
- 一款逼疯妹子的撩妹神器
- 美团token解决思路
- 【ESP32 S3开发】在Arduino IDE中使用PSRAM
- java一维数组输入整数n_用键盘接受输入的整数,将输入的整数保存到一个一维数组,然后输出最大值...
- Python生成图文并茂PDF报告
- 揭秘阿里员工每天必刷的内网
- IDEA起步(一) - 工程结构
- php面试php数组变ahp,php实现把数组按指定的个数分隔
- 玩转华为ENSP模拟器系列 | 配置OSPFv3 ABR路由聚合示例
- HDU 3236 Gift Hunting (程序猿的哄女朋友方式)