大家好,我是练习UE4时长两年半的TA工具人。

最近的项目里大量使用UE4引擎。这引擎更新速度和幅度相当给力,今年发现两年半之前学的知识都已经过时了,很多东西又得重新捡起梳理。所以后面会更新一些UE4相关的内容,于我自己是学习笔记;至于你们怎么看我就不知道了。

这一次谈的内容是在UE4中实现 动态的液体材质,这个材质会实时识别和其他物体的交互,在交互区域根据需求改变流向,改变材质表现等等。最后的效果酷炫,在项目中可能使用概率较高。

这个方向网上能找到的资料相对稀少,并且现在能查到的做法(2019 0713)我并不是很认可。我觉得我的实现思路更加直观、清晰,可控性和可拓展性都优秀很多。

感觉不太正确的参考资料:

Distance Field Flow Map​forums.unrealengine.com

https://www.youtube.com/watch?v=chPIKqa-0zk

使用版本:

UE4 4.22.3

涉及主要知识点:

DistanceToNearestSurface 节点、DistanceFieldGradient节点介绍与实战使用。

初等数学应用(主要就是向量)

水的基本流动

水材质我用的UE4自带的starter content里的M_Water_Lake,然后在这个简单材质上做了很多魔改。跟本文主题相关的内容后面会慢慢讲,关系不大的就跳过了。

水的基本流动原理非常简单,就是UV偏移。使用一个Panner节点就可以做出来了。下图是我用的,带有uvRepeat次数,以及可以调节流动方向的节点网。

现在的水就可以根据我们定义的 (speedU,speedV)这个二维向量来决定水的流向,但现在还只是最基本的效果。

可以看出水在流动的过程中,和周围的物体完全不产生交互关系。后面我们要着手改进这一点。


水流受物体影响分析

目前我们的水体流动如图所示,纯粹是对贴图进行一个方向的偏移的结果。

如果我们想要水流和图中的圆球产生交互,最终水流应该是什么样的流向呢?想象一下,一定是绕着这个圆球继续往下流

如果我们只利用UV偏移的思路,怎么实现这样的效果呢。我们对比一下原来的流动轨迹 和 目标流动轨迹,来分析一下两者之间的关系。

如图示可以看出,大致上,原本的流向,按照球结构本身的点法线方向往外推,就可以实现我们的目标。

另外,随着离开球的距离越来越远,这种水流流向的改变效果应该会越来越弱。直到足够远之后,原本的流向完全不再改变,这才是符合自然规律的效果。

经过以上非常不严谨的推测,最终结论就是,我们需要获得两个信息:

1.球体与水面接触处的点法线方向

2.水面上的点的位置离球体的距离


distance field简单介绍

在UE4中已经有一个现成的节点,可以实时获取通过DistanceToNearestSurface 这个节点拿到。

按字面意思大致理解, 这个节点会返回到自己最近的模型上的点离自己的距离是多远。

这样说还是有点抽象,不好理解;本质上来说,这个节点计算的是距离场(distance field)

距离场在图像处理领域,以及三维渲染领域用的都非常多,相关资料非常丰富。

现在我在SD里演示一下距离场的具体表现效果。使用节点 Bevel(本质是distance节点,也就是SD中算距离场的节点)

原始图像
distance为正值
distance 为负值
动态效果

可以看出,距离场其实就用图像亮度 记录 某个点 离最近的图像边界的距离


在UE4中拿取distance field相关信息

我们在材质面板常见一个DistanceToNearestSurface 节点,输入口提示需要输入position信息。这里我们只要传递进世界位置信息就可以用了。

输出口我们先挂在材质的自发光上观察这个节点计算出来的结果。

使用一个面片赋予刚做的材质来观察效果。结果却一直是纯黑,看起来不对。为什么呢?

这是因为UE4里要计算distance field,有一个全局的开关。这个材质节点只是拿取全局计算完的信息来用。如果开关没开,其实是没有计算信息的,就算创建了DistanceToNearestSurface 节点,也拿不到想要的信息。

所以先要在项目设置里开启 distance field 的计算:

Project Settings>Rendering>Generate Mesh Distance Fields

开启功能重启编辑器之后,这个材质就有了效果:

因为计算出的数值非常大,我乘了一个非常小的系数。纯粹是为了观察。

动态效果

通过DistanceToNearestSurface 节点,我们可以有自信说,可以拿到距离信息进行后续操作了。

但是相交位置的点法线信息怎么办呢?

UE4里还有另外一个节点可以干这个事,叫DistanceFieldGradient。

计算出来的结果如下图所示。这个节点是既带有方向又带有距离的,正好符合我们的需求


DistanceFieldGradient节点初探

我们先连一套节点来测试一下,这个DistanceFieldGradient节点,在UV上的作用具体是什么样的。

原理很简单,就是用自己原本的UV减掉DistanceFieldGradient计算出来的向量,这样就可以做出沿着 相交区域点法线方向向外推贴图的效果。

下面节点中,normalize是官方推荐要连的。

UV是一个二维向量,我们只用DistanceFieldGradient节点的RG两个通道和UV进行相减计算。下面乘的pushAmount是控制效果强度的,0.01这个参数是让pushAmount不要太敏感,调参数的时候手感舒服一点,没有功能意义。

现在已经实现了我们预期效果的一部分了。

但是现在看起来有点问题,就是这个图被切成一个圆形了,外面的信息全没了。

这个问题我现在还没完全搞明白,感觉应该是DistanceFieldGradient这个节点本身计算有点问题,最外面的信息不完全是纯黑导致的。

现在尝试优化这个问题。

优化切割问题

优化的思路也比较简单直接。就是使用距离信息,大于某个指定距离值以外的向量,强行指定为(0,0)。

有了思路以后,我们就开始具体操作。首先我们要通过距离算出一个mask,这个mask的最外面是黑色,越往内越亮,直到纯白。

这里就可以使用之前介绍过的DistanceToNearestSurface节点来获得距离信息了。因为默认算出来的距离是纯物理数值;也就是说,某个点离最近交点距离为4.13个单位远,那么该点的亮度就是4.13 。

如果我们想要指定的范围就是4.13,那么用DistanceToNearestSurface 节点计算出来的结果 除以4.13 ,那么4.13距离处的亮度现在就是1,从球表面到4.13距离处的亮度变化变为0 - 1了。

最后再加个1-x ,clamp掉超过1的亮度,就获得了我们想要的mask效果了。 最后加一个power是调节过渡的软硬程度的。

该部分节点如下

distance参数的效果
power参数的效果

再把做好的信息加上逻辑判断,mask等于0的亮度全部输出(0,0),大于0的亮度还是用原来的向量。

另外,按官方文档说DistanceFieldGradient是带有距离信息的,但是我感觉最后效果不明显,所以把DistanceFieldGradient计算出来的向量还乘了一次DistanceToNearestSurface的mask信息,这样就可以产生一个柔和的从内到外的过渡效果。

加上UV流动以后

但现在有个问题。感觉从周围绕开的效果太均匀了,和整体流动的大方向关系不明确。下面我们再尝试加入更多的方向性。


扰动带有方向性

原理依然非常简单—— 在原来的扰动向量基础上,再加一个方向向量。

这里我们使用的方向向量就是水流的流动方向,可以直接使用之前定义好的那个控制方向的二维方向向量。

这个向量第一次乘的是之前的distanceMask,第二次乘的是我们要控制的强度,然后直接加上去就好。

调节这个向量影响程度的过程中,可以看到,扰乱的效果出现明显的拖尾。目标达成。

整体改变流向的效果。

最后一个问题,非世界空间!

以上大体的效果上的东西,我们做得差不多了。但是其实这里还遗留了一个很大的坑。

我们到目前为止测试的效果都是在平面上的,如果把这些片放倾斜,效果就会出毛病!

怎么忽然就做出了个螺旋丸了呢???

其实问题是这样的。之前我们计算的DistanceFieldGradient结果是一个三维向量,代表的是距离场在世界空间里的朝向。而前面我们偷懒直接提取的RG两个通道当UV来用。

如果面片正面朝天,那么RG两个通道正好代表的XY轴向正好和UV的方向重合,只有在这种特殊巧合下,前面的做法才成立。而一旦面片进行了旋转,这个巧合就被粉碎。螺旋丸就产生了。

所以现在我们要想办法把所有的计算都拿到真正的世界坐标下去计算

如下图所示,假设任意一个DistanceFieldGradient节点计算出来的向量(x,y,z),直接拿取它的xy作为UV偏移量来算显然是错的。

真正能用做UV偏移量的向量,应该是(x,y,z)向量在U方向(红轴)的投影长度,和V方向(绿轴)投影长度,组合而成的二维向量。

UV二轴原本单位向量分别为(1,0) 和(0,1),这个向量是切空间的(tangent space),不能直接拿来和世界空间的向量进行运算。

想要对二者进行计算,我们就需要将切空间的向量转换成世界空间的向量。

UE4中有一个节点TransfromVector(Tangent Space to World Space)就是做这个事情的。(搜索transform创建的就是这个节点)

这个节点输入的是三维向量,所以我们创建一个(1,0,0)和(0,1,0)来代表切空间的UV单位向量,再通过TransfromVector将他们转到世界空间。

转换完成之后,再和给定向量(x,y,z)进行点乘,计算出来的两个分量合在一起的二维向量就是真正可以使用的UV偏移向量。

之前我们用if节点算完的结果就是我们上面假定的那个向量(x,y,z),这部分节点的组织方式如下图。

当然这样一改,会有部分报错,原因是三维向量和二维向量不能放在一起计算。我们将之前某些用二维向量的地方全部改成三维向量就好了。

做完的一套节点大概如图:

最后,在一个球体上,无论什么角度,都不会出错。

最后

写完了,花了好多时间。

这篇文章也只是介绍了一个大框架,具体想要更好的效果还有非常多可发掘的地方。

比如用算出来的距离信息去做一些置换什么的,用数学方法算出一些mask,决定哪些地方会出现泡沫等等。

我自己在项目里的运用比文章里写的这些内容也是复杂很多倍。

开篇发的两个链接里的做法,通过一些数学方法重算了近似点法线方向的信息,但严格上来说,那个信息是不准确的;虽然从最后的结果上看,是没有问题。但是在后续做更复杂的效果的时候,他们那样算出来的信息不准确,不利于后续计算。我是觉得那样做的可拓展性不够。

这点大家可以一起讨论一下。

整篇下来其实我自己觉得唯一有意思的部分是最后空间转换的思路,这个没查到资料,是我自己忽然顿悟想出来的。那种感觉太爽了。

这也是在UE4里做材质有意思的地方吧。

ue4缓存位置怎么改_[UE4]动态液体材质浅谈相关推荐

  1. ue4缓存位置怎么改_怎么从蓝图节点跳转到C++源码?

    在以前的虚幻编辑器版本上,通常是这样打开C++代码的:双击蓝图节点,或者在蓝图节点上右键,再点击Goto Definition,这样就自动打开VS,跳出C++代码来了. 但是,从某个版本开始,这样忽然 ...

  2. c++怎么确定一个整数有几位_德国人怎么学电机——浅谈电机模型(十六):同步电机(三)永磁电机(一)...

    上一章传送门: 善道:德国人怎么学电机--浅谈电机模型(十五):同步电机(二)凸极电机​zhuanlan.zhihu.com 同步电机能够类似直流电机,除了电励磁也可以直接使用永磁体来励磁.这样转子上 ...

  3. ad6怎么画电阻_德国人怎么学电机——浅谈电机模型(十七):同步电机(四)永磁电机(二)...

    上一章传送门: 善道:德国人怎么学电机--浅谈电机模型(十六):同步电机(三)永磁电机(一)​zhuanlan.zhihu.com 本章节如果未加说明,都以转子表面贴片的永磁电机为例. 7 电流和电压 ...

  4. ue4渲染速度太慢_[UE4]性能优化指南(程序向)

    封面来源:A Cold Stop(Mixer 制作材质.UE4渲染 ) [UE4]性能优化指南(美术向)玄冬Wong:[UE4]性能优化指南(美术向)​zhuanlan.zhihu.com 内容都是处 ...

  5. ue4蓝图碰撞检测的类型_[UE4]武器碰撞

    转自:https://www.cnblogs.com/corgi/p/5405454.html 实现武器战斗伤害系统,击中时如何发出碰撞事件产生伤害,目前探索的有通过物理碰撞和LineTrace两种方 ...

  6. sql server的密码采用自带什么密码技术存储_【技术分享】浅谈MYSQL 8.0新特性

    于树文 云技术管理处 01 MySQL 8.0中添加的功能 1. 新的系统字典表 整合了存储有关数据库对象信息的事务数据字典,所有的元数据都用InnoDB引擎进行存储. 2. 支持DDL 原子操作 I ...

  7. pymysq向mysql写数据 为什么本地无法查看_从运维角度浅谈MySQL数据库优化,中小企业DBA必会...

    原文:http://www.enmotech.com/web/detail/1/712/1.html(复制链接,打开浏览器即可查看原文) 作者:搬砖游击队 一个成熟的数据库架构并不是一开始设计就具备高 ...

  8. url采集工具_大数据关键技术浅谈之大数据采集

    在前几篇文章中,企通查为大家介绍了大数据处理的基本流程.从大数据的一系列处理过程中(抽取.集成.分析.解释),我们可以发现这一整套流程中涵盖了数据存储.处理.应用等多方面的技术. 大数据价值的完美体现 ...

  9. mysql x key 组合_技本功丨浅谈MySQL的七种锁

    作者:宋丹琪(花名:三思)袋鼠云云服务部DBA团队 数据库工程师 时常会有开发的同学突然紧张兮兮地找我, 然后丢给我一个代码层面的 CannotAcquireLockException的报错, 一脸无 ...

  10. securecrt遇到一个致命的错误且必须关闭_高性能服务器之路 | 浅谈 Valgrind 内存错误检查神器 Memcheck...

    本文是 高性能服务器开发 第一篇 导读 Memcheck 可以检查哪些内存错误? 使用 Memcheck 解决问题的原则 原则 1,内存非法读写错误一定要解决 原则 2,变量未初始化错误一定要解决 原 ...

最新文章

  1. 2021年大数据Flink(十四):流批一体API Connectors JDBC
  2. Stm32学了好久了,为什么做项目还是力不从心?
  3. mysql提供的六种约束_SQL的六种约束
  4. JS 对象(Object)和字符串(String)互转
  5. (68)SPI工作模式有哪些?分为几种极性模式。
  6. 那些坑爹的老代码,究竟改还是不改?!
  7. 【每日一博】asynchat 异步socket命令/响应处理器
  8. Java学习之路 之 提问及解决篇
  9. php兼容net的md5,解决c# md5与php md5加密不一致的问题(md5(unicode))
  10. 1. 走进Java语言 —— Java SE
  11. Java借助百度云人脸识别实现人脸注册、登录功能的完整示例
  12. 区块链赋能金融科技!2018 PPP全球数字资产投资峰会在京召开
  13. QQ向陌生人聊天的autoit脚本
  14. 深度模型训练之learning rate
  15. 全面接入:ChatGPT杀进15个商业应用,让AI替你打工
  16. 受了点小伤,心情怎么就变坏了呢?
  17. 【OpenCV-Python】教程:5-3 光流
  18. 前端利用js里数组的filter方法进行多条件过滤查询
  19. .net5 查询Access数据库数据
  20. 换脸新潮流:BIGO风靡全球的人脸风格迁移技术

热门文章

  1. 【手势识别】基于matlab肤色静态手势识别【含Matlab源码 288期】
  2. 【图像加密】基于matlab DNA混沌系统图像加密【含Matlab源码 1190期】
  3. 【图像处理】基于matlab直方图医学图像处理【含Matlab源码 458期】
  4. Matlab R2020a版安装下载详细操作步骤【Matlab 140期】
  5. 液晶显示器尺寸对照表_安徽CHARACTER液晶显示屏
  6. ROBOTSTXT_OBEY
  7. mysql员工与部门代码,springMVC入门实例(员工系统-Mysql)代码简单易懂
  8. 【C++】一次遇到的需要加入const属性的情况
  9. lte基站可以做ntp server吗?_你手机信号强吗?学会这几招快速提升你的手机信号...
  10. cef 加载flash 弹框_cef 3.2357之后加载flash的方法