在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中实现基于粒子的水模拟(三:混合屏幕)相关推荐

  1. 在Unity中实现基于粒子的水模拟(二:开始着色)

    在Unity中实现基于粒子的水模拟(二:开始着色) 文章目录 在Unity中实现基于粒子的水模拟(二:开始着色) 前言 一.生成顶点 二.偏移模拟 1.接收细分着色器输出的顶点 2.根据数据调用对应的 ...

  2. 在Unity中实现基于粒子的水模拟

    曲面细分进行水模拟(一:物理模拟) 文章目录 曲面细分进行水模拟(一:物理模拟) 前言 一.曲线模拟的原理介绍 二.代码计算终点 1.代码原理介绍 2.第一条射线计算 3.第二条射线计算 4. 分配数 ...

  3. 在Unity中创建基于Node节点的编辑器 (二) 窗口序列化

    孙广东  2018.5.13 csdn 的产品 , 真垃圾, 不想吐槽了, 文章保存就丢!     没办法  .    怎么不满意, 还是得继续用, 哎~~~ 第二部分 在Unity中序列化基于节点的 ...

  4. 在Unity中创建基于Node节点的编辑器 (一)

    孙广东   2018.5.13 Unity  AssetStore中关于Node节点 编辑器相关的插件可是数不胜数, 状态机,行为树,Shader 可视化等等. Unity自己也有 Animator的 ...

  5. 学习在Unity中创建一个动作RPG游戏

    游戏开发变得简单.使用Unity学习C#并创建您自己的动作角色扮演游戏! 你会学到什么 学习C#,一种现代通用的编程语言. 了解Unity中2D发展的能力. 发展强大的和可移植的解决问题的技能. 了解 ...

  6. 【Unity学习笔记】Unity中的欧拉角(Euler Angle)和万向节(Gimbal)

    声明:此篇文章是个人学习笔记,并非教程,所以内容可能不够严谨.可作参考,但不保证绝对正确.如果你发现我的文章有什么错误,非常欢迎指正,谢谢哦. 目录 1 奇怪的现象 1.2现象一 1.2 现象二 1. ...

  7. Unity中的灯光和渲染

    一:Unity中的灯光 --Directional Light:模拟太阳光.它与位置无关,是平行光,可以调整旋转角度模拟昼夜 --Spot Light:模拟车灯.手电筒的光.舞台灯光 --Point ...

  8. 【Unity3D Shader编程】之五 圣诞夜篇 Unity中Shader的三种形态对比 混合操作合辑

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  9. Unity 中的声音系统

    Unity 支持的音频格式 AIFF 最适合短音效果 可以在编辑器中按需求压缩 WAV 最适合短音效果 可以在编辑器中按需求压缩 MP3 最适合较长的音乐曲目 OGG 压缩音频格式(与iPhone设备 ...

最新文章

  1. python笔记6 模块与包 程序开发规范 包 re sys time os模块
  2. 译者招募 | 这本“顶级”微积分教材,中文版要来了!
  3. 连接阿里云和容器技术生态 - 阿里云开源容器项目汇总
  4. python安装后无法运行任何软件_为啥我按照python安装教程,总说无法启动此程序,因为计算机中丢失?...
  5. CVE-2012-4792Microsoft Internet Explorer 释放后使用漏洞
  6. 系统设计(二)——TinyURL系统设计
  7. (day 37 - 动态规划)剑指 Offer 46. 把数字翻译成字符串
  8. kubernetes Pod yaml解析注释
  9. mysql集群脑裂问题_redis集群怎么解决脑裂问题
  10. java编程新手初学者入门学习,看什么书比较好
  11. matlab 非线性辨识,非线性系统辨识Matlab实现
  12. 【人工智能】180页PPT,讲解人工智能技术与产业发展
  13. Python基础_闭包和迭代器
  14. 【人脸识别项目一】:眨眼检测
  15. Hypervisor介绍
  16. XXE漏洞(XML外部实体注入)
  17. CentOS 7 从本地 ISO 映像文件安装 Gnome GUI
  18. 用计算机可以干嘛的,计算机还可以做什么?
  19. Tsar学习笔记---tsar tsar2db mysql 集成调测篇
  20. 百度ECharts地图GeoJson数据在线下载 2021

热门文章

  1. 一款逼疯妹子的撩妹神器
  2. 美团token解决思路
  3. 【ESP32 S3开发】在Arduino IDE中使用PSRAM
  4. java一维数组输入整数n_用键盘接受输入的整数,将输入的整数保存到一个一维数组,然后输出最大值...
  5. Python生成图文并茂PDF报告
  6. 揭秘阿里员工每天必刷的内网
  7. IDEA起步(一) - 工程结构
  8. php面试php数组变ahp,php实现把数组按指定的个数分隔
  9. 玩转华为ENSP模拟器系列 | 配置OSPFv3 ABR路由聚合示例
  10. HDU 3236 Gift Hunting (程序猿的哄女朋友方式)