您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 qq_微愿_kzk 于 2022-8-17 17:26 编辑
Introduction
Greetings adventurers! I’m Asher Zhu, currently Senior Tech Artist at Epic Games, making video game technology that appeared in my dreams. I like blowing things up and passing you the TNT formula.
Here is a most recent Elden Ring fanart VFX I made:
介绍
问候冒险家!我是Asher Zhu,目前是Epic Games的高级技术美术师,正在制作出现在我梦中的视频游戏技术。我喜欢把事情搞砸,把TNT公式递给你。
以下是我最近制作的Elden Ring粉丝艺术VFX:
I was in indie. Making cool games has always been my favorite game. And I’m sure a lot of you feel the same. During the dark nights, I coded, designed, and made VFX. I was proud of them. And they got me into Epic.
我当时是独立游戏。制作很酷的游戏一直是我最喜欢的游戏。我相信你们很多人都有同感。在漆黑的夜晚,我编码、设计和制作视觉特效。我为他们感到骄傲。他们让我进入了Epic。
Since then, I've been stubborn to make every effect I created a mini-game on its own. Some gained popularity among gamers and developers alike. It's been an awesome experience to spread joy and inspiration this way while working for a big company.
从那时起,我一直固执地将我创建的每个效果都制作成一个迷你游戏。有些在游戏玩家和开发人员中都很受欢迎。在为一家大公司工作时,以这种方式传播快乐和灵感是一次很棒的经历。
Niagara Fluids
For starters, Niagara Fluids includes templates for fire, smoke, pools of water, splashes, and shallow water. It’s UE5’s answer to fluid simulation. Niagara is the most robust, artist-friendly GPU programming framework for video games (or for anything, really). Niagara Fluids is basically a DLC that makes fluid-related stuff much easier.
尼亚加拉流体
对于初学者来说,Niagara Fluids包括用于火,烟雾,水池,飞溅和浅水的模板。这是UE5对流体模拟的回答。Niagara是视频游戏(或任何东西)最强大,艺术家友好的GPU编程框架。Niagara Fluids基本上是一个DLC,它使与流体相关的东西变得更加容易。
The tool's main features:
Simulation:
FLIP solver for water (2D and 3D)
Shallow water implementation
Gas simulation for both 2D and 3D grid
A series of Niagara System showcases
该工具的主要功能:
模拟:
FLIP 水求解器(2D 和 3D)
浅水实施
2D 和 3D 网格的气体模拟
尼亚加拉系统展示系列
Rendering:
SDF/jumpflood renderer
Material to represent SDF using Single Layer Water
(coming soon) Sphere rasterizer that supplements SDF
Lighting injection Interfaces for gas
Epic Games的高级技术美术师Asher Zhu分享了虚幻尼亚加拉流体工作流程的巨大分解,解释了如何设置水面和白水粒子,谈到了如何使水模拟的颜色科学准确,并分享了一些代码片段。
介绍
问候冒险家!我是Asher Zhu,目前是Epic Games的高级技术美术师,正在制作出现在我梦中的视频游戏技术。我喜欢把事情搞砸,把TNT公式递给你。
以下是我最近制作的Elden Ring粉丝艺术VFX:
我当时是独立游戏。制作很酷的游戏一直是我最喜欢的游戏。我相信你们很多人都有同感。在漆黑的夜晚,我编码、设计和制作视觉特效。我为他们感到骄傲。他们让我进入了Epic。
从那时起,我一直固执地将我创建的每个效果都制作成一个迷你游戏。有些在游戏玩家和开发人员中都很受欢迎。在为一家大公司工作时,以这种方式传播快乐和灵感是一次很棒的经历。
尼亚加拉流体
对于初学者来说,Niagara Fluids包括用于火,烟雾,水池,飞溅和浅水的模板。这是UE5对流体模拟的回答。Niagara是视频游戏(或任何东西)最强大,艺术家友好的GPU编程框架。Niagara Fluids基本上是一个DLC,它使与流体相关的东西变得更加容易。
该工具的主要功能:
模拟:
FLIP 水求解器(2D 和 3D)
浅水实施
2D 和 3D 网格的气体模拟
尼亚加拉系统展示系列
渲染:
SDF/jumpflood 渲染器
使用单层水表示 SDF 的材料
(即将推出)补充 SDF 的球体光栅化器
气体照明注入接口
Gameplay/Interaction:
3D Collision Interfaces
2.5D Collision (affect 2D sims with 3D world object)
Character interaction
游戏玩法/互动:
3D 碰撞接口
2.5D碰撞(影响2D模拟与3D世界对象)
角色互动
And more! It’s critical to download Content Example and open the Niagara_Fluids map yourself. You can wander through the workflow demos and see what’s available. All Content Examples maps are constantly updated to reflect UE’s latest features.
还有更多!下载内容示例并自行打开Niagara_Fluids地图至关重要。您可以在工作流演示中徘徊,并查看可用的内容。所有内容示例地图都会不断更新,以反映 UE 的最新功能。
The Fluid Simulation Experiment
Engineered art and artistic tools have always been my curiosity, and I’ve done many experiments to see how far I could go. There were plenty of skill trees I had to master before I could unlock the fluid simulation skill tree.
流体模拟实验
工程艺术和艺术工具一直是我的好奇心,我做了很多实验,看看我能走多远。在解锁流体模拟技能树之前,我必须掌握很多技能树。
It’s a long story, but I’d like to mention a couple of toys I made that helped me understand volumetric effects. Firstly, clouds! Stacking 3D noises together to create beautiful clouds was extremely satisfying. Painting them was just a very natural next step. The process trained me to visually feel the fluffy and crispy shapes of 3D noises. It’s very similar to water splashes, foam, and bubbles, in terms of techniques and mood. Here is my breakdown article if you are interested.
这是一个很长的故事,但我想提一下我制作的几个玩具,它们帮助我了解体积效应。首先是云!将3D噪声堆叠在一起以创建美丽的云层是非常令人满意的。粉刷它们只是一个非常自然的下一步。这个过程训练我直观地感受到3D噪音的蓬松和脆皮形状。就技术和情绪而言,它与水溅,泡沫和气泡非常相似。如果您有兴趣,这是我的细分文章。
After that, the uncharted domain of FluidSim (for artists) caught my attention. Niagara Sim Stage was rapidly maturing at that time and I gave it a go. I read papers. I got totally lost after a couple of pages. But I kept pushing. In a couple of months, my system started to take shape. To this day I still can’t believe it worked.
在那之后,FluidSim(针对艺术家)的未知领域引起了我的注意。Niagara Sim Stage当时正在迅速成熟,我试了一下。我读论文。几页后,我完全迷失了。但我一直在努力。几个月后,我的系统开始成形。直到今天,我仍然不敢相信它奏效了。
Eventually, my OC character Barrelhead was born.
Around that time I had to create most of the modules and materials from scratch. SPH solver, rasterizer, collision. There weren't good ways to communicate with Secondary Emitters(more of this below) so I had to ‘morph’ a small percent of SPH particles into splash sprites.
最终,我的OC角色Barrelhead诞生了。
大约在那个时候,我不得不从头开始创建大部分模块和材料。SPH 求解器、光栅化器、冲突。没有与次级发射器通信的好方法(下面会详细介绍),所以我不得不将一小部分SPH粒子“变形”为飞溅精灵。
With the advancement of Niagara, now we have robust pre-made alternative modules, with showcases to help you learn and make well-informed decisions. I think 2022 is a really good year to get into it.
If you are new to procedural VFX in general, check out the base knowledge first. From there, your second stop will be Epic’s Learning Library, search ‘"Niagara" and give it a go. There are dozens of extremely well-constructed examples crafted by our engine dev team, tech writers, and evangelists. A lot of questions you have, and a lot of questions you don’t know you should have, will be answered while learning to replicate these cool toys.
随着Niagara的进步,现在我们拥有强大的预制替代模块,并带有展示柜,可帮助您学习并做出明智的决策。我认为2022年是进入它的好年头。
如果您不熟悉程序化视觉特效,请先查看基础知识。从那里,您的第二站将是Epic的学习图书馆,搜索“尼亚加拉”并尝试一下。我们的引擎开发团队、技术作者和布道者精心制作了数十个构建精美的示例。你有很多问题,很多你不知道你应该有的问题,在学习复制这些很酷的玩具时会得到解答。
As for the FluidSim learning path, I personally recommend brute-forcing the Content Examples. Problem-solving is the best way to learn.
Deconstructing and reconstructing demo assets in this order has worked for me the best:
至于FluidSim学习路径,我个人建议对内容示例进行暴力破解。解决问题是最好的学习方式。
按以下顺序解构和重建演示资产对我最有效:
Check out all the examples play with the parameters. Check out the official Niagara Fluid intro videos.
Stripe out the renderer ‘beauty’ components and everything not essential to the simulation
Leave out a minimal ‘barely working’ system
Dissect further with the assistance of Debug Tools and Attribute Spreadsheet
Learn to create new custom modules to make stuff happen
查看所有使用参数的示例。查看官方尼亚加拉流体介绍视频。
剥离渲染器的“美”组件和对模拟
不重要的所有内容 省略最小的“勉强工作”系统
在调试工具和属性电子表格的帮助下进一步剖析
学习创建新的自定义模块以使事情发生
Setting Up the System
Simulation
We start with the Simulation part, all the 3D water simulation in Niagara uses a PIC/FLIP module. As mentioned above, you can find these examples in the Niagara_Fluids map:
设置系统
模拟
我们从模拟部分开始,尼亚加拉的所有3D水模拟都使用PIC / FLIP模块。如上所述,您可以在Niagara_Fluids地图中找到这些示例:
From a high-level overview, there isn't too much to tweak here – which is good. Because water is water, you don’t typically want different kinds of water.
从高层次的概述来看,这里没有太多需要调整的地方 - 这很好。因为水就是水,所以你通常不想要不同种类的水。
To get a feel of the parameters, a brief explanation of stuff that matters:
Collision Velocity Mult: Used for collision interaction. For example, consider pouring water out of a bowl. If this is 0, you can’t pour the water no matter how fast you try. Water will simply flow down with gravity.
Geometry Collection Collisions: Works with Chaos fracture asset! Still WiP though.
Static Mesh Collision: It samples individual static mesh distance field (NOT global distance field). You have position, normal, and velocity for the nearest surface point at your disposal. It also doesn’t require global DF generation so won’t affect Niagara System tick order. Aka can be used with Opaque materials without 1 frame delay.
Num Cells Max Axis: Pick the longest axis of your bounding box. Divide the length with this number, you get your simulation voxel size. Just a convenient way to set & tweak resolution for everything.
Particles Per Cell: Utility parameter to fill a tank of water on sim start.
Physics Collisions: Character collision using Physics Asset DI, here's a great tutorial on the topic.
Pressure Iterations: We can bind a dynamic number to determine how many times we want a render stage to iterate. For water systems, this determines Solve Pressure sim stage iterations count.
PIC FLIP ratio: 0.0 - 100% PIC simulation, stable, less accurate. 1.0 - 100% FLIP simulation, accurate, less stable. A value in between – mix good things of both. Usually, 0.75 - 0.95 works well depending on your use case (e.g. fish tank or running river).
为了了解参数,请简要说明重要的东西:
碰撞速度增加:用于碰撞交互。例如,考虑从碗中倒出水。如果这是0,则无论您尝试多快,都无法倒水。水会随着重力而流下来。
几何体集合碰撞:与混沌断裂资产一起工作!不过还是WiP。
静态网格体碰撞:它对单个静态网格体距离场(不是全局距离场)进行采样。您拥有最近表面点的位置、法线和速度。它也不需要全局DF生成,因此不会影响Niagara系统刻度顺序。Aka可以与不透明材料一起使用,没有1帧延迟。
细胞数最大轴:选取边界框的最长轴。将长度除以此数字,即可得到模拟体素大小。只是一种设置和调整所有内容分辨率的便捷方法。
每个细胞的颗粒数:实用程序参数,用于在sim启动时填充水箱。
物理碰撞: 使用物理资源DI进行角色碰撞,这是关于该主题的一个很好的教程。
压力迭代:我们可以绑定一个动态数字,以确定我们希望渲染阶段迭代多少次。对于供水系统,这决定了求解压力模拟阶段迭代计数。
PIC翻转比:0.0-100%PIC模拟,稳定,精度较低。1.0 - 100%翻转模拟,准确,稳定性较差。介于两者之间的价值 - 将两者的好东西混合在一起。通常,0.75 - 0.95效果很好,具体取决于您的用例(例如鱼缸或流淌的河流)。
Collision
Static meshes are amazing. Their collision is accurate and we can pre-generate mesh distance field for them. With Geometry Cache collision still in an experimental state, Static Mesh collision is the best to stir interesting fluid behavior.
碰撞
静态网格体令人惊叹。它们的碰撞是准确的,我们可以为它们预先生成网格距离场。由于几何缓存冲突仍处于实验状态,静态网格体冲突是激发有趣的流体行为的最佳选择。
The Niagara_Fluids map river uses Static Mesh Collisions DI, which is what I’d recommend. This interface takes the Mesh Distance Field (not Global Distance Field) of all tagged static meshes. As a result, you get view-independent collision, normal and velocity reads. The downside is it gets heavier the more meshes you mark for collision.
Niagara_Fluids地图河流使用静态网格体碰撞DI,这是我推荐的。此接口采用所有标记静态网格体的网格距离字段(不是全局距离字段)。因此,您将获得与视图无关的碰撞、法线和速度读取。缺点是它越重,您标记为碰撞的网格越多。
An alternative is the Global Distance Field collision. Because global SDF is constantly generated as a whole in runtime, the cost is always the same. The downside is it’s view dependent. Your water may pop a little when the camera gets further/nearer. And it doesn’t support mesh velocity.
另一种方法是全局距离场碰撞。由于全局 SDF 在运行时作为一个整体不断生成,因此成本始终相同。缺点是它依赖于视图。当相机越来越远/更近时,您的水可能会弹出一点。而且它不支持网格速度。
There are also other collision types for Landscape and Skeletal Mesh.
景观和骨架网格体还有其他碰撞类型。
Rendering
My river demo and all the Content Example 3D fluids use the Single Layer Water shading model. It’s basically a 3D box masked out to match the shape of the water body.
渲染
我的河流演示和所有内容示例 3D 流体都使用单层水着色模型。它基本上是一个3D盒子,被遮盖起来以匹配水体的形状。
Because we know the water surface depth from SDF, we can ‘push’ the SLW material pixel onto the correct position using Pixel Depth Offset. Water surface normal is also extracted from SDF. With all these combined, we can render the volume of the water. But how do we get more art-directed elements to make the water prettier?
由于我们知道 SDF 的水面深度,因此可以使用像素深度偏移将 SLW 材质像素“推”到正确的位置。水面正常也是从自制铁中提取的。结合所有这些,我们可以渲染水的体积。但是,我们如何获得更多的艺术导向元素来使水更漂亮呢?
Working with Whitewater
For video game water, foam or ‘white water’ is often a generalized name for 3 parts: Splash, Surface foam, and Bubbles.
Note: Artistically and technically, all of these also more or less apply to 2D water simulation, shadow water, or even traditional mesh/flowmap-based water effects. Pick what’s useful to you.
与白水合作
对于视频游戏水,泡沫或“白水”通常是3个部分的通用名称:飞溅,表面泡沫和气泡。
注意:在艺术和技术上,所有这些也或多或少地适用于2D水模拟,阴影水,甚至传统的基于网格/流图的水效果。选择对你有用的内容。
Splash
In video games, water splash is almost always presented as flipbook sprites. For 2D water surfaces, we can decide where and when to spawn splashes using 3D geometry representation and water velocity. Consider boulders sitting in the middle of ocean waves, or the player interacting with a river – we can tell that, part of them is underwater simply by comparing their height with the water's surface height.
溅
在视频游戏中,水花几乎总是以翻盖精灵的形式呈现。对于 2D 水面,我们可以使用 3D 几何表示和水流速度来决定在何处以及何时生成飞溅。考虑一下坐在海浪中间的巨石,或者玩家与河流互动 - 我们可以通过简单地将它们的高度与水面高度进行比较来判断,其中一部分在水下。
For 3D simulation, not much has changed for the 3D geometry representation (of things to collide with), however, we do need to refer to the Grid3D to find out where to spawn the sprites. That’s where the Secondary Emitter in NiagaraFluids plugin chimes in (you can find it in the examples).
The Secondary Emitter will check these conditions for all SimGrid voxel positions:
Distance Field - Is this point inside water?
Grid Velocity - Is water here moving fast enough?
Grid Vorticity - Is water here volatile enough?
If all are satisfied with one voxel, secondary particles will spawn at the position of that voxel (with a little jittering on top to smooth things out).
对于3D模拟,3D几何表示(与之碰撞的事物)没有太大变化,但是,我们确实需要参考Grid3D来找出生成子画面的位置。这就是NiagaraFluids插件中的二次发射器(您可以在示例中找到它)。
次级发射器将检查所有 SimGrid 体素位置的以下条件:
距离场 - 这个点在水里吗?
网格速度 - 这里的水移动速度是否足够快?
网格涡度 - 这里的水足够挥发吗?
如果所有人都满足于一个体素,则次要粒子将在该体素的位置生成(顶部有一点抖动以平滑事物)。
Water surface only:
仅水面:
WIth Splash sprites:
飞溅精灵:
Sprites visualization:
精灵可视化:
Within the Secondary Emitter, you have nice control of how and when the sprites should spawn:
在辅助发射器中,您可以很好地控制子画面的生成方式和时间:
The secondary particles are rendered as flipbook sprites, the animation starts to play the moment they spawn. I prefer dithered Masked flipbooks for splash instead of Translucent because they are cheaper, can sort against each other, and can have pixel normal to react to environmental light. Translucent sprites can have pixel normal if you want, but when you have a lot of secondary particles, the pixel details tend to blur each other out.
次要粒子被渲染为翻页子画面,动画在它们生成的那一刻开始播放。我更喜欢抖动的蒙版翻页书而不是半透明,因为它们更便宜,可以相互排序,并且可以具有正常像素来对环境光做出反应。如果你愿意,半透明的精灵可以具有正常的像素,但是当你有很多次要粒子时,像素细节往往会相互模糊。
Bubbles
Masked material writes Depth buffer, which also means it affects underwater light scattering for Single Layer Water material. Here is an exaggerated example that has the water darkened, so you can see the underwater sprites' color behavior more easily:
泡沫
遮罩材质写入深度缓冲区,这也意味着它会影响单层水材质的水下光散射。下面是一个夸张的示例,它使水变暗,因此您可以更轻松地看到水下精灵的颜色行为:
When the slash sprites are underwater, the scattering totally makes them look like bubbles. And I just used that, with a little opacity tweak. Of course, you can do more fancy tricks on pixel shader to make it look even more interesting.
当斜杠精灵在水下时,散射完全使它们看起来像气泡。我只是用了它,稍微调整了一下不透明度。当然,您可以在像素着色器上做更多花哨的技巧,使其看起来更有趣。
Foam
Attention adventurers, for water foams, we are traveling to the “this will be in the next UE release” city. Mainly because we’ll need a few additional modules. Rasterization and DualRestPosition are two of them.
泡沫
冒险家们注意,对于水泡,我们正前往“这将在下一个UE发布”的城市。主要是因为我们需要一些额外的模块。光栅化和双列位置是其中的两个。
For now, I’ll go over the stuff I did and provide code samples (attached at the end of this section). If you are eager, it’s a good opportunity to dive into the HLSL craziness.
For clarity, I use the SDF approach to render water surfaces because I like the look better. But all particle-carried attributes are extracted using rasterization (written as Niagara modules). See below for details.
现在,我将回顾我所做的工作并提供代码示例(附加在本节末尾)。如果你很渴望,这是一个潜入HLSL疯狂的好机会。
为了清楚起见,我使用 SDF 方法来渲染水面,因为我更喜欢水面。但是所有携带粒子的属性都是使用光栅化(写成Niagara模块)提取的。有关详细信息,请参阅下文。
Dual Rest Field
So, Dual Rest Position Field (sometimes it’s easier to refer to the result – advected textures) is similar to flowmaps. However, instead of predefined flow directions on a 2D texture, the direction data is carried on discrete particles and rasterized in real-time:
双静止场
因此,双静止位置字段(有时更容易引用结果 - 平移纹理)类似于流图。但是,方向数据不是在 2D 纹理上预定义的流向,而是在离散粒子上进行并实时栅格化:
This, of course, is better explained in cat memes:
Rasterize Foam Intensity to ScreenSpace
But how do we know where the foam is, and communicate that to the material? Similar to the Secondary Emitter, we calculate Foam Intensity on each particle. And we rasterize it on a screenspace RT.
Foam Intensity RT in screenspace, visualized as a heatmap:
当然,这在猫咪模因中得到了更好的解释:
将泡沫强度栅格化为屏幕空间
但是,我们如何知道泡沫在哪里,并将其传达给材料呢?与次级发射器类似,我们计算每个粒子的泡沫强度。我们在屏幕空间RT上将其栅格化。
屏幕空间中的泡沫强度 RT,可视化为热图:
And we blur out the Foam Intensity RT using Render Target 2D – Mip Map Generation
我们使用渲染目标 2D – Mip 贴图生成模糊泡沫强度 RT
Finally, we can multiply that advected foam texture (again, cat meme texture) with the foam intensity RT.
最后,我们可以将平移的泡沫纹理(再次,猫模因纹理)与泡沫强度RT相乘。
That still feels too ‘dry’ for some reason, like pouring baby powder into the river. There is only so much we can do on the surface. It lacks volume. That’s where the splashes come to the rescue:
由于某种原因,这仍然感觉太“干燥”了,就像将婴儿爽身粉倒入河中一样。在表面上,我们能做的只有这么多。它缺乏音量。这就是飞溅来拯救的地方:
They add an essential volumetric feel on top of the surface. The dithered splash also ‘smears’ the pixels between water and foam, which yields a really nice soft feel.
它们在表面顶部增加了基本的体积感。抖动的飞溅还“涂抹”了水和泡沫之间的像素,从而产生了非常好的柔软感。
Now, both foam and surface detail normal texture is added to the water surface using this technique. Foam does drastic modifications to pixel basecolor, roughness, opacity, specular and normal, while detailed normal texture simply applies to water surface normal(where foam is absent). More on this later.
现在,使用这种技术将泡沫和表面细节正常纹理添加到水面。泡沫对像素底色,粗糙度,不透明度,镜面反射和正常进行大幅修改,而详细的正常纹理仅适用于水面正常(没有泡沫)。稍后将对此进行详细介绍。
Foam Tips
Focus on using large advected foam texture for punch. Then add small foam texture for detail.
泡沫提示
专注于使用大的平移泡沫纹理进行冲孔。然后添加小泡沫纹理以获得细节。
If you only focus on detail. You’ll get something like this. Looks nice but doesn’t feel natural. The flow feels forced.
如果你只关注细节。你会得到这样的东西。看起来不错,但感觉不自然。这种流动感觉是被迫的。
In the surface material, keep foam intensity RT (from the simulation) smooth and untouched. Don’t tweak its contrast. A simple SmoothStep is enough. To create contrast, manipulate the advected foam textures (cat meme) instead.
I don’t have pictures for this one because it’s more of a feel. Basically, you want to art direct the foam texture, but not the physics. Foam intensity RT is physics.
在表面材料中,保持泡沫强度RT(来自模拟)光滑且不受影响。不要调整它的对比度。一个简单的 SmoothStep 就足够了。要创建对比度,请改为操纵平移的泡沫纹理(猫模因)。
我没有这张照片的照片,因为它更像是一种感觉。基本上,你想艺术地指导泡沫纹理,而不是物理。泡沫强度RT是物理学。
Phase Function
I kind of brushed over the detail normal layer from the last session. The reason is once you understand the foam part, hooking up the detail normal texture would be trivial. Detail normal is great for still or slowly moving water surfaces. However, for chaotic running water, your mileage may vary. Personally, when using translucency with TAA/TSR, I found it hard to keep the fine details intact.
But it’s still an amazing layer of important detail. We can use it to interact with lighting. Firstly, the detail normal twists the underlying caustics in a nice way and ‘pushes’ the caustics forward:
相位功能
我稍微刷了上一节课的细节普通层。原因是一旦你了解了泡沫部分,连接细节的正常纹理将是微不足道的。细节法线非常适合静止或缓慢移动的水面。但是,对于混沌自来水,您的里程可能会有所不同。就个人而言,当将半透明性与TAA / TSR一起使用时,我发现很难保持精细的细节完好无损。
但它仍然是一个惊人的重要细节层。我们可以用它来与照明进行交互。首先,细节法线以一种很好的方式扭曲了潜在的焦散,并将焦散向前“推”:
Secondly, you may have noticed the sparks are a little more interesting and reactive as a result. This is because the sparks come from the reflection of the sun. And the reflection takes water normal, including detail normal as input.
Finally, another important technique is using phase function to add fake light scattering.
其次,您可能已经注意到火花因此更加有趣和被动。这是因为火花来自太阳的反射。反射需要水正常,包括细节正常作为输入。
最后,另一个重要的技术是使用相位函数来添加假光散射。
Directionality input of the phase function is taken from detail normal texture, and it’s an excellent way to add fidelity for volatile water, as well as a great opportunity to add some color variation. Notice the scattering light added in the right gif is a little greener than the watercolor.
相位函数的方向性输入取自细节的正常纹理,这是为挥发性水增加保真度的绝佳方法,也是添加一些颜色变化的绝佳机会。请注意,在右侧GIF中添加的散射光比水彩画绿一点。
Code Examples
RasterizeParticlesAsSpheres:
代码示例
光栅化粒子为球体:
After we get the depth RT, we can do the sphere trace again to rasterize ExecIndex onto another RT.
获得深度 RT 后,我们可以再次进行球体跟踪,以将 ExecIndex 栅格化到另一个 RT 上。
WritingExecIndexByComparingSphereDepth:
通过比较球体深度来编写Exec索引:
for(int i = -RadiusIndexExtent.x; i <= RadiusIndexExtent.x; i++)
{
for(int j = -RadiusIndexExtent.y; j<= RadiusIndexExtent.y; j++)
{
int2 CurIndex = ParticleIndex + int2(i, j);
if(CurIndex.x >= 0 && CurIndex.y >= 0 && CurIndex.x < NumCellsX && CurIndex.y < NumCellsY)
{
float2 VectorFromCenter = ((float2)CurIndex + float2(.5f, .5f)) / float2(NumCellsX, NumCellsY) - ParticleUV;
float2 OffsetWS = VectorFromCenter / RadiusInUV;
// Treating camera as orthographical but shouldn't be noticeable since spheres are small?
OffsetWS *= OffsetWS;
float t = 1 - OffsetWS.x - OffsetWS.y;
// Inside sphere mask
if(t > 0)
{
float DepthOffset = sqrt(t) * RadiusWS;
float OriginalValue;
float ThisDepth = ParticleClip.w - DepthOffset;
RasterGrid.GetFloatGridValue(CurIndex.x, CurIndex.y, 0, 0, OriginalValue);
if(abs(ThisDepth - OriginalValue) < .1f)
{
ExecIndexGrid.SetFloatValue(CurIndex.x, CurIndex.y, ExecIndex);
Yes, I’m doing the sphere tracking twice. It’s not the best but at the moment RasterGrid can’t carry additional attributes so we have to do some tricks. This process does have room to improve. Either way, to boost performance, it’s important to define a strategy to keep track of particles that are ‘too deep’ under the surface and cull them from the rasterization.
是的,我正在做两次球体跟踪。它不是最好的,但目前RasterGrid不能携带其他属性,所以我们必须做一些技巧。这一过程确实有改进的余地。无论哪种方式,为了提高性能,重要的是要定义一个策略来跟踪表面下“太深”的粒子,并将其从光栅化中剔除。
In the case of SPH sim, we have the luxury of knowing each particle’s neighbors. But for Eulerian simulations or Eulerian/Lagrangian hybrid simulations (e.g. FLIP), we don't know how many particles are nearby.
So how do we know which particles are ‘too deep’? For my demo, since SDF is the field we use to generate water surfaces, it contains the best information to make that call. Current frame SDF can be used to cull current frame particles from rasterization. Previous frame SDF can be used to cull current frame particles from SDF generation.
在SPH sim的情况下,我们可以了解每个粒子的邻居。但是对于欧拉模拟或欧拉/拉格朗日混合模拟(例如FLIP),我们不知道附近有多少粒子。
那么,我们如何知道哪些粒子“太深”呢?在我的演示中,由于 SDF 是我们用来生成水面的字段,因此它包含进行该调用的最佳信息。当前帧 SDF 可用于从栅格化中剔除当前帧粒子。上一帧 SDF 可用于从 SDF 生成中剔除当前帧粒子。
From there, it’s easy to extract any attribute you want from the particles.
Grid2D_VorticityFromExecIndex:
从那里,很容易从粒子中提取所需的任何属性。
Grid2D_VorticityFromExecIndex:
The rest of the code examples take too much space. So I uploaded it to my Discord server. You can download the zip here.
Dual Rest Position Field:
DualRestTimeline: Goes into Emitter Update
DualRestCapturePosition: Goes into Particle Update
rid2D_PixelDualRestPosition: As a Simulation Stage. This takes a ScreenSpace depth grid as input to calculate the offset between surface pixels and particle rest positions.
其余的代码示例占用太多空间。所以我把它上传到我的Discord服务器。您可以在此处下载 zip。
双静止位置字段:
双RestTimeline:进入发射器更新
DualRestCapturePosition: 進入粒子更新
rid2D_PixelDualRestPosition:作为模拟阶段。这将采用 ScreenSpace 深度网格作为输入,以计算表面像素和粒子静止位置之间的偏移。
SDF raymarch:
Grid3D_RaymarchSDF: You can feed the rasterized sphere depth directly as input for Grid2D_PixelDualRestPosition. But it’s much nicer to have the SDF surface as input to get more accurate and smoother results.
The raymarched result can also be used directly for rendering (in material). The content example does the raymarching step inside the material.
SDF raymarch:
Grid3D_RaymarchSDF:您可以直接将栅格化球体深度作为Grid2D_PixelDualRestPosition的输入。但是,最好将 SDF 表面作为输入,以获得更准确、更平滑的结果。
射线处理结果也可以直接用于渲染(在材质中)。内容示例在材质内部执行光线处理步骤。
Opacity and Colors
For colors, apart from the techniques already mentioned, it’s also important to understand the science behind the UE’s water surface material, namely the Absorption and Scattering Coefficient.
In short, as of 2022 all video games still use RGB values to represent color. Spectral rendering is a luxury we are yet to have.
不透明度和颜色
对于颜色,除了已经提到的技术之外,了解UE水面材料背后的科学也很重要,即吸收和散射系数。
简而言之,截至2022年,所有视频游戏仍然使用RGB值来表示颜色。光谱渲染是我们尚未拥有的奢侈品。
The benefit is, for any light calculation, we only have 3 channels to worry about. In the case of water absorption, think of the primary colors – Red, Green, and Blue as three types of light energy we have in the game world. And when the light goes underwater, water will take some of the energy away from each primary color, before the light can hit our eyes (the camera). Obviously, water absorbs red more than blue. That’s why water is blue.
But how much is each primary color absorbed? In order to answer this question, first, let’s check Wikipedia for the wavelength of each RGB channel.
好处是,对于任何光计算,我们只需要担心3个通道。在吸水的情况下,将原色 - 红色,绿色和蓝色视为我们在游戏世界中拥有的三种类型的光能。当光线进入水下时,在光线照射到我们的眼睛(相机)之前,水会从每种原色中带走一些能量。显然,水比蓝色更能吸收红色。这就是为什么水是蓝色的。
但是每种原色被吸收了多少呢?为了回答这个问题,首先,让我们检查维基百科中每个RGB通道的波长。
So, proximately:
Red: ~700nm
Green: ~550nm
Blue: ~450nm
No need to be too precise here. We are artists, we can do whatever we want.
Next, let’s look up the water absorption coefficient:
因此,近似地:
红色: ~700nm
绿色: ~550nm
蓝色: ~450nm
这里没有必要太精确。我们是艺术家,我们可以做任何我们想做的事情。
接下来,让我们抬头看看吸水系数:
This is more science than video games, but we only need to understand a small part of it.
So, for the red channel, the wavelength is around 700nm, and from the chart, we get the Absorbance coefficient = ~0.6/m. This means when the light goes into the water, its Red energy will be reduced to a portion of 1/e after the light travels a distance of 1/0.6 = 1.667m. Similarly, Green energy will be reduced to 1/e after the light travels 1/0.05 = 20m. Blue energy will be reduced to 1/e after the light travels 1/0.005 = 200m.
And the math ends here, well done! Now we only need to fill the Absorbance values into Single Layer Water material.
这比电子游戏更科学,但我们只需要了解其中的一小部分。
因此,对于红色通道,波长约为700nm,从图表中,我们得到吸光度系数= ~0.6 / m。这意味着当光进入水中时,在光行进1/0.6 = 1.667m的距离后,其红色能量将减少到1/e的一部分。同样,在光传播1/0.05 = 20m后,绿色能量将减少到1/e。在光传播1/0.005 = 200m后,蓝色能量将减少到1/e。
数学到此为止,干得好!现在,我们只需要将吸光度值填充到单层水材料中即可。
There you go, if you got here you have nailed the most important part of making a beautiful water surface material. The water shading model will take water depth and handle the calculation of absorption.
I’d also recommend checking out Ryan Brucks’ “Water And Volumetrics - Inside Unreal” talk for a deeper dive into this topic:
如果你到了这里,你已经确定了制作美丽水面材料的最重要部分。遮水模型将取水深并处理吸收的计算。
我还建议看看Ryan Brucks的“水和体积学 - 虚幻内部”演讲,以更深入地探讨这个话题:
https://youtu.be/XHugDXx6c5c
For the FluidSim project, I kept the Scattering at almost zero because I’m putting another layer of foam on top of the water, and I wanted high contrast between the clear water and the foam layer. The foam material was made into a Material Attribute and blended with water surface material inside the same SLW material.
对于FluidSim项目,我将散射保持在几乎为零的水平,因为我在水面上放了另一层泡沫,并且我希望清水和泡沫层之间的高对比度。将泡沫材料制成材料属性,并与同一 SLW 材料内的水面材料混合
Last but not the least, caustics is an essential part. It adds details, and most importantly it gives you a way to control underwater brightness without messing with the water light response. As mentioned, the animated caustics patterns also play very nicely with refraction from moving waves.
最后但并非最不重要的一点是,苛性碱是必不可少的部分。它增加了细节,最重要的是,它为您提供了一种控制水下亮度的方法,而不会弄乱水光响应。如前所述,动画焦散图案也很好地配合了移动波的折射。
What Should One Consider When Working With Niagara?
Apparently, when we talk about an ‘experimental’ tool the first thing that pops up in our head is – bugs! Or, it still can’t do the so, so obvious thing you want it to do yet.
与尼亚加拉合作时应该考虑什么?
显然,当我们谈论“实验性”工具时,我们脑海中浮现的第一件事就是 - 错误!或者,它仍然不能这样做,所以你希望它做的显而易见的事情。
Personally speaking, while it’s not production ready, it’s simply fun to jump in and learn how future video game magic will work. Professional-wise, it’s always a ping-pong situation between technology and creative space. Bugs are artificial forms of the unknown, if you don’t fiddle with the darkness, you’ll only be able to do the stuff that everyone has already done. The process of problem-solving and banging my head on the wall always led to a deeper understanding of what I wanted to do and how to turn that creative space into reality.
就个人而言,虽然它还没有准备好生产,但跳进去学习未来的视频游戏魔术将如何运作只是很有趣。在专业方面,它始终是技术与创意空间之间的平局。虫子是未知的人造形式,如果你不摆弄黑暗,你只能做每个人都已经做过的事情。解决问题和把头撞在墙上的过程总是让我更深入地了解我想做什么,以及如何将创意空间变成现实。
That being said, if you follow our question 3 here and the showcases, I believe you’d have a kinda smooth experience. The system is pretty robust for what we have already tested. Be aware of the cost, any FluidSim effect is likely going to cost a big chunk of your game’s render budget. Profile in Standalone play mode often and plan ahead.
话虽如此,如果你按照我们的问题3在这里和展示,我相信你会有一个有点顺利的体验。对于我们已经测试过的内容,该系统非常强大。请注意成本,任何FluidSim效果都可能花费游戏渲染预算的很大一部分。经常在独立游戏模式下配置文件并提前计划。
The good news is all the modules are going to improve under the hood over time. So what costs you 12ms now has a good chance to cost much less in the future. But how much? We’ll only know after the change and do extensive profiling.
好消息是,随着时间的推移,所有模块都将在引擎盖下得到改进。因此,您现在花费12ms的费用很有可能在未来花费更少的成本。但是多少钱呢?我们只会在更改后知道并进行广泛的分析。
Regarding putting the new systems into your game, if your game is in pre-production or in early stages with enough time budget for R&D, It’s always good to push for more novelty. Set up scenes to profile simulation performance under different scalability settings (particle count, grid resolution, rendering, etc.). Focus on art-directed supplement techniques, instead of relying on simulated resolution. This will go a long way.
关于将新系统放入游戏中,如果您的游戏处于预生产阶段或早期阶段,并且有足够的时间预算进行研发,那么推动更多的新颖性总是好的。设置场景以分析不同可伸缩性设置(粒子计数、网格分辨率、渲染等)下的模拟性能。专注于艺术导向的补充技术,而不是依靠模拟分辨率。这将有很长的路要走。
If your game is deep in production and you are wondering if the new fancy thing is good for the next milestone. Unless you are absolutely sure about what you are doing, and have an abundant margin for error, please don’t. The crunch is not worth it. So many unfamiliar and strange things can go wrong. All my friends, especially our beloved producers, will hate you and warn people about you. As a game company, we should know better than risk crunching our teams. This might sound harsh but I’ve seen so many horror stories.
如果你的游戏正在深入生产,并且你想知道新的花哨的东西是否适合下一个里程碑。除非你绝对确定自己在做什么,并且有很大的犯错余地,否则请不要这样做。紧缩是不值得的。许多不熟悉和奇怪的事情可能会出错。我所有的朋友,尤其是我们心爱的制片人,都会恨你,并警告人们关于你的事情。作为一家游戏公司,我们应该知道得更多,而不是冒险处理我们的团队。这可能听起来很刺耳,但我看过很多恐怖故事。
Conclusion
Thank you for having me. I use Twitter mostly to promote my creations and techniques. It’s weird to think Twitter is widely adopted for academic purposes. Also, my ArtStation always has the best quality videos.
结论
谢谢你邀请我。我主要使用Twitter来推广我的作品和技术。认为Twitter被广泛用于学术目的很奇怪。此外,我的ArtStation始终拥有最高质量的视频。
|