>>Amanda: Hey, folks! Wrapped up your shift with
the free Factory Environment? Epic Games has collaborated
with Unreal Engine Marketplace creator and creative
studio SilverTM to bring an expansive 200 acre
urban park to all Unreal Engine creators for free. The City Park
Environment Collection contains everything you'd expect
in a large outdoor environment, from winding walking trails
to fun-filled playgrounds and quiet greens for
the perfect picnic. Stop by the Marketplace to
download the free collection. Are you interested in the
emerging field of in-camera VFX as seen in the production of
'The Mandalorian', but not sure how to get started? Well you're in luck! We've created a new In-Camera
VFX Example project that will guide you through the various
steps you need to configure the system on a single
machine--a setup you can then expand to multiple machines
in your production deployment on stage. The project is accompanied
by comprehensive step-by-step documentation to guide you
through how the pieces all fit together. Download the new example
project from the Learn Tab in the Epic Games launcher. Tossing over to our top
weekly karma earners. Many thanks to these folks
who are helping others on AnswerHub: Everynone, Expose, Tuerer,
ClockworkOcean, Shadowriver, MMMarcis, PixelOmen, T_Sumisaki,
DonBusso, and Chatouille. Now hopping over to our
Community Spotlights: You won't get bored
playing Let Them Trade, a minimalistic trading
simulation in which you build a network of towns. As the king,
expand your kingdom and secure trade routes between your
towns, keeping supply and demand in balance. Wishlist Let Them Trade
on Steam and keep an eye on their Twitter for
development updates! Easily configure loading
screens in your projects with this free Async
Loading Screen Plugin. Automatically add
new loading screens whenever you open a new level,
use pre-designed UI layouts and default icons,
or customize your own! Download the plugin for
free on the Marketplace. And last up is the bright and
fun, atmospheric adventure platformer Soria. Inspired by Scandinavian folklore, take part in a
journey of friendship and found family that
explores the bond between a fledgling
gryphon and a young boy as they discover the secrets
of a mysterious golden castle. Try out a demo of Soria on Itch.io today and follow them
on Twitter @Polargryph! Thanks for watching this week's
News and Community Spotlight. >>Victor: Hi, everyone,
and welcome to Inside Unreal, a weekly show where we
learn, explore, and celebrate everything Unreal. I'm your host, Victor
Brodin, and my guest today is our Principal Technical
Artist Ryan Brucks. Welcome to the show. >>Ryan: Hi, everybody. So today we wanted to
take this opportunity to go ahead and talk about some
of the upcoming water features that we've all been working
on for Unreal Engine 4.26. So this is something that we've
been working on for a while now, and we've kind of needed
a water solution in Unreal for a number of years. But with Fortnite Chapter 2, that was a good opportunity
for us to push on water. So what we did is we
formed a strike team with a bunch of people
from different initiatives or different teams-- a couple
of people from rendering, a couple of people from tools,
couple people from gameplay, me from tech art,
along with some help from a few other individuals. And then what we did is
we made the water system for Fortnite Chapter 2 based
off of some GPU terrain modeling methods. And what that system allows you
to do is define in the editor using splines where all the
water features are going to go. And the goal of it was to have
a unified surface as a result, so level designers
wouldn't have to be going anymore and seaming up
splines, connecting to lake meshes,
and blending them out, and fiddling with terrain
curves and all this stuff. We just basically wanted to be
able to say, water goes here, and then have the level
designers go in and place it. So we were able to get
something working for Chapter 2, and now what we're trying to do
is clean that up and deliver it to Unreal Engine at large so
that everyone else can use it. It took a little bit longer
than initially planned because we had to maintain
backwards compatibility, all the while adding new
things, but I think we're now at a
state where it makes sense to start talking about it and
showing it a little bit more. And of course,
it's not actually accessible just yet,
because this is in a plugin that's in the restricted
part of the depot, but it will be available
in the 4.26 preview stream. But that's probably still a few-- a couple months or at
least out from now. So I'm going to go ahead and
jump into the editor here. I'm going to start with some
really simple test map style examples, and then we'll
progressively build up from just basic water bodies
and basic materials to a scene that's a little bit more
indicative of what you could do with some actual
art and materials, and showing a few of
the ways that we use a system like this in Fortnite. So the first thing you see
with the new water system-- we have these new water
bodies in the world. This is a water
body test map that's going to be with the water
plugin just called Water Body-- Water Test Map. And you can see,
with these water bodies, we now have an
actor for each body. You can move it around, set it
in the right height of the world, and it blends things together. And on these actors,
there's a bunch of settings for things like how
it's going to deform the world. So I guess I'm going to go ahead
and just delete these things, and just place new ones, because it's a little
bit more fun when you can see it from scratch. So this is just a blank
landscape and a blank map, essentially. And then the Place Actors-- let me go ahead and
search for water. And you'll see here we
have a few different water types, like lake,
ocean, river, island. We'll go ahead and
drop down an ocean. So you'll see, what this does, is it actually creates a spline. And now,
wherever we drag this thing, it's making the ocean level
at the height of that actor. But it's also kind
of flattening out an island around this terrain. And there's a number
of things that go into how this
carves the terrain. Let me go ahead make this a
little bit smaller for now. So one thing I'd like to point out is what we have is a curve
to control what ends up being the elevation of the water
under the terrain or the water depth. So I'm going to go over here
on the Water Body settings, under Terrain, Curve Settings. And notice that we
have this curve here. And what this curve does
is it actually represents the profile of that falloff. It's evaluated on the 0 to 1
range, so really just within this kind of
box I've selected here. So it's kind of a nice
S-curve by default. And then what you
can do is control how it's mapped by using
these settings here. So right now this ocean is set
to be 2,000 centimeters, which is 20 meters deep. But we can go ahead and make it
a little bit shallower so it's a little bit more obvious. And we have the falloffs set
to be at about 80 meters. But you know, we can make the
falloff really harsh. We can make it really long. Or we can kind of keep
it back where we had it. So while we're
looking at that curve, what we could actually do if
we wanted to-- and this is something we end
up tweaking a lot, but it's nice to know
that it's there-- is-- let me try to make
this a little bit more visible for you. When I'm placing
these points in here, these are actually
affecting the profile a lot. And it can be nonlinear. Not a very interesting example. But you can see that I've
made kind of a concentric ring in the falloff there. So it really allows
you to customize the profile of your
water features. And then of course how these
things work is they get added to a layer in the new
Landscape > Edit Layers system. So you'll just end up with a new
layer, called 'Water'. And then you can just tick
it on and off as you want. And the neat thing about
that, though, is you can still actually
hand-paint inside that layer. And that allows you
to make up for some of the things that are not
controllable as per point attributes. And we'll go into some
more detail about that in a little bit as well. But for example, let's go ahead
and make a bigger brush here. >>Victor: Hey,
Ryan, just a quick note that I'm getting
heavily compressed and poor quality, unfortunately,
through Discord right now. >>Ryan: That's too bad. It was really good when
we first started the test. >>Victor: Mm-hmm,
and yesterday as well. >>Ryan: So
hopefully it improves. Do you think people can still
at least see the programmer art content? I'm hoping it improves when
I get to the actual art. >>Victor: Let's
switch over to the editor. It's not even actually
loading, where everything is still right now. I'm not sure what's going on. Hey, OK, let's do this real quick. Ryan, why don't you restart
your stream real quick. >>Ryan: Sure. You mean just the screenshare? >>Victor: Yes. So stop streaming. And then I'm going to close that. Let's go ahead and
get it back up again. >>Ryan: Sorry, folks. Bear with us. Any improvement? >>Victor: Yes,
that is a lot better actually. All right, cool. Sorry, all. It looks good. Now let's everyone hold
your thumbs and toes and whatever else you
want to hold to make sure this stays up. Please, go ahead, Ryan. >>Ryan: No worries. All right,
so what I'm trying to show here is that you can still go
ahead and create another paint layer on top of Water to
apply some custom changes, if you wanted to have the
beach be a little bit softer, higher,
or just really sculpted out. And what that's really
doing is storing the delta between what was
there and what was under. So if I unhide Water
now, you'll still see I have a little bit
of this kind of paint that I did before. But you can always
just clear that, or you can go in and paint black
to erase it and clear that. All right, so that's basically
how the water depth is defined. It's defined using this curve. And there's some
additional options for how far you want
to offset this thing. You can tell it to have a
big, flat area. But then there's
also the component of how does it carve
the rest of the terrain. You'll notice that we're kind of
creating a little valley there. And that's basically
using this setting called Water Heightmap Settings. And that's a struct that defines
a bunch of different settings. We're going to go ahead
and stick to the falloff settings for now. And you'll notice that right
now this is in Angle mode. So as I move this thing down, it's essentially going to
cut the rest of it to try and get an angle. And you can change that
angle to be shallow, steep, or keep it as it was. Or you can also set it to Width
mode, which in that case, now it's not going to be an angle. It's just going to
be a constant falloff so that you can kind of
control exactly how that's going to apply. And the Edge Offset
here is kind of separate from the curve offset. So you really have a
separate two-way control for your edge offsetting,
which is pretty powerful. And below the basic
falloff settings for things like width and angle,
there's these effects areas. There's a little bit of blurring, because right now these
shapes are actually generated on the distance
field using jump flooding. So that process,
when it's not done at a super high resolution,
can pick up a little bit of alias-y artifacts. If I turn off blurring-- it's
on, by default, at 2. And that pretty much fixes it. But you can adjust it as
needed to kind of smooth out the result. But you'll notice that that's
blurring the actual distance field result,
not the height result. So you'll notice that no matter
how blurry I set that, it's not going to blur this top edge. That's actually
something different. That's actually this
smooth blending step here. So I can go ahead and
change Smooth Blending between inner and
outer separately. So Inner Smooth smooths the
inside, as you can see there. Then an Outer Smooth
smooths the outer side. So you really have separate
control over the plateauing. There's also some
kernel noise options. But I'm going to refrain
from showing those right now because they're a little
bit broken with water. They're more of a
landmass feature. But you're free to add in noise
just by perturbing your points, doing whatever. I'm going to go
ahead and remove some of that crazy edge offsetting. And then we can go
ahead and recreate a little bit of that
scene we had here before. So now we have an ocean. Let me go ahead and drop in-- how about a lake? So one thing that is a
limitation with the system right now is it will not blend,
say, a lake with an ocean. So if you try to put
a lake overlapping an ocean, what you're going to get is something a little weird. But what you can do is place
them at the same z-height. And then you could
use the material to fade in some
custom stuff there. So we do this in Fortnite a
lot, is for the swamp, what we actually do is we have
a lake there at sea level. And then we replace
the material on it. And it has some sort of mask that colorizes just that region. But generally,
when you're placing a lake, you have these part
of the terrain, and then probably
connected with a river. So let's go ahead and do that. So one thing to note
about rivers is, currently, they are explicit. They won't try to
automatically connect to the height of
the ocean or lake. So it's good to be
aware of the heights that you're going to
put your lakes at. So I'm just going to go ahead
and put that one to zero and ocean at 768,
just so that now, when I drag in this river you'll
notice the river dragged in is zero. So it's already blended in. And we do get automatic
blending of the terrain height between water and rivers. You'll notice that the
river blends into the lower depth of the lake. And the same thing will
happen with the ocean once we set it at
the correct height. It's just that here we
have the river too high. Let me go ahead
and make this ocean bigger so I have more
room to play with. OK, so now that we have
these spline points, let me go ahead and
point out-- right now, not all of the defaults
on these new actors are what they will be in the end. We expect we will probably
include things like a wider falloff default, for example. Because there are certain
limitations with the way that the water is rendered. And we'll get to
that in a little bit. Let me go ahead and set
that river down to 768. Oops. I did that wrong. I moved the whole thing. What I meant to do was,
in Selected Points, when you select your water spline, you can now go down
here, under Water. This shows all of the water
properties such as depth, velocity, and width. But you can also adjust
the point directly. So I'm just going
to go ahead and set these river points to be
exactly at the ocean height. So now we get an automatic blend. And another thing you
probably want to do is set the Velocity at
the endpoint to zero. And it'll automatically
fade out back to whatever the river velocity was. And depending on the shape
of each specific river, you might want to adjust
things like the z-offsetting. In this case,
I can tell we're getting a little bit of this
river bleeding over here. We can offset the z-height
of the terrain a little bit to fix that. And then the other
thing that's causing this is I know, from experience,
that the tangents aren't flat. So this river is
actually going downhill. What we need to do there is
just simply select the arrive and leave tangents,
and set them to zero. And you can tell we overshot
our z-offset a little bit now. Let me go ahead and reduce that. There we go. So yeah, with adjusting
things like the z-offset of the terrain on the water body, you can get a pretty
smooth transition. And then going up here, let me go ahead and
select this point. Set its velocity to zero as well. And this is actually a good
time to show visualizers, which if you saw my Unreal
Fest/ was a GDC talk, you've already seen this. But what we can do now is
just show these visualizers for width and depth. And start to just play with
them directly in the editor-- or sorry,
directly on the component without selecting things
and typing separate values. Let me just come in and
kind of do what feels right. We have some really
deep, crazy spots. But it's not quite what we want. OK, and then of
course also there's velocity,
which acts very similarly. I don't have foam yet hooked
up inside of this shader but what it's doing is it's
changing the flow map strength. So as you increase velocity you
will see the flow map increase. But by the time we ship this,
we do plan to add the foam back. And that's what Fortnite
does, is it basically has, in the material, it reads this velocity
from the water body, and then uses it to apply
some masking for some foam that shows up. And we can actually see
what that looks like now. And I guess I'll back up a
step here and mention that how these guys are all rendered. So these are all separate actors. As we mentioned, they're all
just different water bodies. But they're all being
rendered by the same actor. So in the world now
you'll see we've got a pretty simple scene. We've got our landscape,
and basic lights, and our water bodies. But then we have this water mesh
actor, and also the water brush actor. We can ignore that guy. You don't really need
to think about him. The water mesh actor, though, this is actually what's doing the
final rendering for the water. So we can go ahead and
jump into Wireframe mode. And we can see that,
how it refines based on distance. And we have this one
unified surface that's kind of connecting everything. So even though these water bodies are separate actors,
what they're doing is they're communicating their
material back to the main water system or the water actor. And we can actually-- I'm looking for the
WaterMeshShowTileBounds one. That will show you how
this water mesh actually gets broken up behind the scenes. So blue is ocean tiles,
red is river, green is lake, and then yellow and purple
are the transitions. And that's important when we start to talk about things
like shader complexity. Because we do extra things like
the flow maps on the river. But we don't want to have
to pay for the flow map out in the ocean. So what we do is we
restrict the flow map to being only on the river
or the transition tile. And then what we do is we
mask out using velocity. So technically you always want
rivers to have some velocity. You could actually cause bugs
if you selected all river points and set no velocity. And I'll show you why that is. Let me go ahead and set Velocity
on these points to zero. And what that does, we're going to now see a little bit
of a seam between these two, where the river and lake connect. And that's because
what we're really doing is using velocity,
behind the scenes, as kind of a way to blend
between the different waves of the different water bodies. But before we go into waves, which I think will be the next thing
that we talk about after this, I'd like to talk just
briefly about the water mesh and the type
of shading that it uses with the new single-layer
water shading model. So I'm going to go
ahead and hide this guy. And what I have here
is just a water plane. So going back in time to when you had to place a static mesh
for a river or a lake, and then you realized,
oh god, it doesn't fit. I have to go in and
make a custom mesh. So we're going to use this just
to kind of show a really basic single-layer water material. So this material here is
similar to the ocean one we were already looking at,
but it's kind of bare bones. So this is the basic
single-layer water. You can see here this is
the Material Attributes pin. And all that's
really going in here is we have this
WaterTextureSurface node. What this really is is this acts
as both the far-away normal map replacement-- so we're mostly
rendering Gerstner waves for the normal map of the water. But far away,
they get too alias-y. So we fall back to just
simple painting textures. But it also reuses
that texture lookup to apply a very faint detail
texture near the camera as well. And this is all
pretty standard stuff. Most of it's defined by
this Water Attributes, which is pretty much just setting
the specular, the roughness, the refraction. And there's a little bit of kind
of the fading of the refraction with depth in here as well. But the Water Attributes is meant to be-- this is just the very
basic constants of water, no textures or anything like that. And then the texture
has the breakup. And then down here is where we get to the actual meat of what's
new with single-layer water. So obviously this material is
using single material attribute pin. But normally this is
the material input. But single-layer water adds this
additional single-layer water material input. And what that does
is it allows you to specify your scattering and
your absorption coefficients. So that's really what
causes the blue coloration and the nice scattering
inside of the water. And this new shading model has
actually been in the engine since 4.24. It was written originally
by Sebastian Hilaire. And it was done for the same
Fortnite water initiative that was mentioned previously. But the reason it went in 4.24 is we don't have a way
for shading models to be easily put in a plugin. So it kind of just had to be. But we hadn't really talked
about it too much yet. But I feel like it might be worth spending a few minutes to
talk about what exactly are these scattering and absorption
coefficients before messing with them. So scattering, I
feel, is more obvious. It's basically how much stuff
like particulates and fog is in the water that's going to
cause scattering or a brighter glow in the water. And absorption is
more, how quickly does light get
absorbed by the water? How quickly does
it lose its energy? And if we want to figure out
the correct way to apply this, we can actually jump
over to Wikipedia to get kind of an idea
of what this means. So absorption
coefficients basically define,
for the visible light spectrum, how much each frequency is
going to be absorbed by water. And you don't really need to
get too deep into the math here. But I'm just using this to
point out that what you can do is look at a chart like this,
which has the absorption spectrum, and you can actually
just kind of pick some RGB colors, and grab the
values from this chart, and then plug them in manually. So we're going to go ahead
and do a quick attempt at that, really quick. But the first thing to
point out is the absorption coefficients are
actually specified using this weird thing
called reciprocal meters. That's this m negative 1 thing. And actually it just
means it's kind of 1/x. And it's just done that
way because the units are in really small values. But you can also convert between
an absorption coefficient and an absorption length. And they're the same
thing, they're just opposite of each other. But personally I find
it a little bit more clear to think in terms
of the absorption length. So you can actually plug
in either absorption length or an
absorption coefficient into the shading model here. You just have to be
aware of that 1 minus x. So what I've done here is actually plugged in the values for RGB
from that chart, manually. And the way that I've
done that-- let's take for example, red. I put 0.6. And how did I come up with that? On here, we can look. 700 nanometers is
roughly the color red. And so what we're
doing here is we're not a full-spectrum renderer. We're rendering in RGB
color, which means we have one channel for
red, green, and blue. So really what we do is we
pick an absorption coefficient for each of those. So we just need to
find the closest value that we can for each of those. So 700 nanometers is a fairly
good representation of red. And this is a log chart. So we can see that we start at
0.1, 0.2, 0.3, 0.4, 0.5, 0.6. So at 700 nanometers,
we have a value 0.6 on there. And what that really
means is that-- how they define this is-- what it really means is
that, after that length, you will have 1/e
left of the water. And that's important to point out, is that because this
is exponential falloff, the intensity of light
will never go to zero, it'll just go to almost zero. But what we can do
is use this to plug in our values in a little
bit more intuitive way. So let's just continue that
with-- green is about like 555. So I basically just
ballparked around here. It's about 0.05. And then for blue,
somewhere around 450 to 420, depending-- and you could
do a lot of research. And there's papers on picking
the correct weighted spectrum tables. But it's probably
not worth it when you're going to be tweaking
the value a little bit anyways. But it comes down to
about 0.005 roughly, somewhere down in this region. And so I've just put that in here. And I've divided it by
100, because this is reciprocal meters. But Unreal takes centimeters. So that's with the physical
values for water absorption from Wikipedia. And it gives a pretty
decent falloff. You can see. And if you want to modify it from
there, what you can do is just add a multiply
to the alpha channel. So this is something I tend
to do in a lot of my shaders, where you have a very
specific color going on. I'll use the alpha as a multiply, just so that you get a
convenient relative thing. And this is especially
important in computer graphics, where this scale may not
always be locked down. But now we can basically
get different varying scales of water absorption by
changing that one scalar. And of course turning on scatter, and you can see it's basically
the fog inside the wire. But now I'm going
to go back to what I was mentioning before about
the absorption length as well. So you'll notice that, in
here, it's pretty much just-- since it's reciprocal meters,
to go to an absorption length, we just have to do 1/x. So what that means is,
instead of writing this out in terms of how quickly light
is absorbed, which is, I feel, not that intuitive,
what you can do instead is write in terms of
how far light goes until you have 1/e left. So how far does most blue go? And if we want to do that,
we're just going to invert this. So I'm going to put
1/x on the color. But before I pass it out, I'm just going to straight-up convert my
existing values by putting 1/x in each channel. So now 1/x for green, 1/x for red. And so now we have these values. And so notice that this
is now a little bit more intuitive if I start to
describe this to you this way. Let me go ahead and
compile this shader. There we go. And as promised, it looks exactly like it did before
we converted it. But now it's a little
bit more intuitive. And we're basically saying,
OK, most of the light goes 200 meters before
it's been absorbed. Most of the red light goes 1.6
meters before it's absorbed. We can set that to 20. And then we're just going to
get purple water because we made the red light go just as far. If we really want to see
that red spread in action, we can get closer to the edge. And probably a good idea-- let me move this outwards
a little bit less, have a steep slope. There we go. So you'll see where you
have a less-steep value. That's where you're really
going to notice the difference between your red absorption. And of course you don't have to
stick to that value from there. I would just suggest to use
that as a starting point. But that's really where
the physical basis of the light
absorption comes from. And that's what the coefficients
versus the attenuation length means. I go ahead and just do
it as attenuation length because I find it to be a little
bit more easy to understand. OK, now hopefully I
haven't bored everybody too much by going off on a tangent about the water scattering. >>Victor: That
was great stuff. >>Ryan: Going to go ahead and delete this
simple mesh that we had and go back to
the water mesh actor. And now we're going to think
about waves for a little bit. OK, so I guess the best
place to look at waves is the ocean, right? So we'll select the ocean. And we're going to go
ahead down here to Wave. Let me make this a
little bit more readable. OK, so now you'll
notice, on a water body, we have this Wave setting,
and we have Wave Source. And right now this is set to
Gerstner Wave Asset Reference. And that actually points
to the content browser. This is something new that one
of the rendering engineers, Kevin Ortegren,
has been working on, that basically waves are now
just an asset that you can place in the content browser. And it's extremely
flexible in the sense that the generator itself can
be changed to different classes of generators. Currently we just have the
simple spectrum generator, which is based on
the one for Fortnite, where essentially you set
how many waves you want, what is the Min Wavelength,
Max Wavelength, the smallest wave and the biggest wave,
how random the directions are, and how steep they are. So you specify just these values, and what it does is it
generates, and randomizes, and gives you all the waves. And this being an asset is useful, because now we don't have
to worry about what if two different maps are supposed
to be in the same locale, and you have to keep on
manually copying waves back. Or two water bodies are supposed
to be shared, like the lake example, you want to make
sure that you reference the same wave asset on
them so that you're never going to have a wave mismatch
between the different materials. But it also can be used even
just as a generator in place. So this is really powerful,
that you can just set randomly-- I want to take these waves and
put them right on this asset. And now I have a generator that
just lives on this water body. And we can go ahead and start
messing with the wavelengths. We'll go ahead and
first say the Num Waves. Now we can increase
this point in time-- currently all the way up to 32. Although it's worth pointing out
that, when this actually ships, we're not planning
on having a max. So that should be cool. It'll be something you'll
have to just figure out, kind of per platform,
what your affordable max is. In theory,
you could have thousands of waves. I'm going to go ahead and make
this look a little bit better. These waves are a
little bit too big. So changing the Min Wavelength
is saying, how short do I want the smallest wave to be. And then the falloff
is the distribution. So with 1 we have a
linear distribution. With 2 we're saying more
and more of the small wave. And if we go too high, eventually it just turns to all noise. And we don't want that. So usually a value around
4 or 3 could be decent. And also something to point out-- notice we're getting these waves
changing drastically a lot. On each water body is this
Wave Attenuation Water Depth. And that's used to specify how
quickly do the waves fade away as they reach the shore. So in this case, since we made our
ocean not very deep, that's why we're not seeing much. Let me go ahead back to
these curve settings. Yeah,
this is only 2.5 meters deep. What is that,
like 10 feet or something? So it's a really shallow,
like a Bora Bora type thing. If we wanted to make this
a little bit better, more realistic,
we'll increase the depth. And then we'll also
increase the width. Sorry, brain fart. So you can tell that
the falloff width that you do under the
terrain, while it affects the terrain underneath,
it's also having just as big of an effect on your waves. So notice before, when I made the waves
a little bit too intense because I had
that falloff too high, this is an example of a bad
default that we'll try to fix. And if I set this to
1, we're going to have absolutely no masking. And then we get these gigantic
waves all the way up to shore-- not very good. So obviously we don't
want to do that. The important thing to note
about the wave attenuation factor is that it's actually
affecting gameplay as well. So that's why it kind of had to be unified as part of the system. Because when you have
a character out here, we need to know-- say, there could be a wave here
that's gigantic, a tidal wave, but it's being masked out. So the gameplay
needs to know to mask out this wave in this location
due to the water depth. So it is handy to be able
to tweak that curved water body as well. Let's go ahead,
just for the heck of it, I'm going to put
a really big wave. So that's the cool thing
about having 32 waves now, is you can put this one really big
wave, and it kind of breaks up our tiling without
having to worry. I'm going to go ahead and look
back at the material real quick again. Because you'll notice
that, before, I mentioned that detail texture. And it's starting to be a problem. So let's take a look. All righty,
so I mentioned before-- or I went over that very
simple single-layer water for just the
texture-based material. But now this is the
single-layer water material that we use for
all water surfaces. So lake, ocean, rivers, and transitions,
they all use this. So we've tried to get
this material down to be fairly cleaned up. Make it a little bit closer. And we'll go through this from
left to right, one at a time, to show what's going on here. And I'll stop when I
get to the problem part. So first and foremost,
here's the new function for computing the Gerstner waves. This basically is a
material function. But it actually bases
on a new code library. And it's able to get all
of the waves with a loop. So there's no more giant node mess of a bunch of functions to
get all these different waves. There's no more material
parameter collection. And Kevin also was able to
make the water data all exist in this new water buffer data. It's an unstructured buffer
that lives behind the scenes. So you can just access
it at any shader by just telling it what's
the water body index. So you'll notice that,
when we place this in a material, we don't really need to say
""water body index"" on it. And the reason why is because,
inside of the default function, the default input is set
to this Water Body Index From Tile Instance. And this calls this code function that Kevin wrote
that just gives you what the index of that water body is and allows it to figure
out the right parameters. But it also means, if you're
in some other random material, all you have to do to get the
waves on this material to match, you go to Wave on your water
body, and you'll see-- hang on. Watch me forget where this is. There it is. You go to Water on
your water body. And it's under Water Body Index. So in this case, ocean is
0, lake is 1, river is 2. But I want to point out,
rivers do not actually have waves. We just set them
to have zero waves. And the reason for that is
because it would be expensive for rivers to have
waves because we'd have to blend between two full
wave sets on the transition tiles. So what we do is we kind of
treat them as an airlock. And also,
rivers kind of have standing waves in real life anyways. They don't tend to have
choppy waves like the ocean. So it didn't make
sense to want to put Gerstner waves onto them. There's some sort of
seam happening up there. I'm not sure what that is. Hmm. Probably related to something
with the depth or something. But maybe figure that out later. All right, so where were we? So with the material-- go back there-- excuse me. OK, so we have this
Gerstner wave function. Great. It gives you the waves. And there's this concept in here
of material attributes called wave attributes. It's not really a proper
structure or anything. It really is just setting
material attribute parameters. It sets material
attributes for normal and it sets them for
world position offset. And the reason that that's pretty handy is when we did this for Fortnite initially,
what we were doing was passing normal and world
position separately everywhere. And it was just always a pain
having these two pins blending. So what we do now is
we pass wave attributes in a bunch of different functions that need to do blending of waves, just know to take these
normal and WPO pins and manipulate them. So for example,
velocity wave mask, this is how it knows how to mask
out the waves using the river velocity. So this is how transitions
are able to work. So there's a couple
of different boxes to opt in to the
transition behavior. And then, on the river,
when you go down to Water, you'll get these two slots,
River to Lake Transition, River to Ocean Transition. And if we pop one of those
open, they don't have anything set except
for they say Enable Lake Transition. And that brings over
those extra instructions for the blending of both behaviors that I was talking about. OK, making some progress. So this is basically how
waves are handled for all of the different permutations. Here is how the water texture
surface is blended to. And I mentioned before I
wasn't happy with the results. And that's because it's
kind of content-dependent. For a real analytical
solution, you need something like lean
mapping, which analytically evaluated the waves to figure
out the right distance to fade. But really what we usually do
here is just kind of specify what's the start
distance, and what's the fade distance for how long
we fade to the normal map plane. So obviously the further you
go with your actual waves, the better it's going to look. But you're fighting
aliasing and noise. So I can go ahead and
increase my screen percentage. And for getting realistic
water rendering, that makes a big difference. And now we're able
to render waves out to a pretty far distance. So that's just something
to keep in mind as you're tweaking is, depending on
the type of waves you have, if I had really
small, noisy waves, I would probably fade to the
normal map a lot quicker. Versus big waves like this,
we push it out a lot further. And of course water
waves are per water body. So we can now come on here and
give this lake its own waves. Let me make them a little smaller. There we go. Oh, I know what's
causing the seam. So you're intended to have
the velocity faded out by the time you get to
the end of the river. So I think if we just select
this point here, and try velocity of 0-- there we go. So that's what I was
mentioning before. We kind of use the velocity
to know where the river is. Because we don't have any
sort of spatial mapping inside the river. All these tiles are actually
the same everywhere. And in fact, we'll show a little
bit more about the material as we step through now. So what happens next is what we do is we set wave
attributes, which is just combining the wave,
normal and world position with these water attributes,
which as before-- we looked at this-- was just the basic
constants for water, specular, and roughness. This Water_Underside,
this is a little function that currently is enabling the
water to also look somewhat correct from the bottom side. So you'll notice,
if we go under the water, I don't have
post-processing in here. In dev rendering right now,
the sky is not showing underwater. So the sky atmosphere
doesn't show underwater. So that's why it's black. But if you put a sky dome,
you will see out of the water now. And you'll see we have kind of
an attempt at some refraction. I'll show this later in
a more realistic map. But that function there is
what's handling basically-- does not want to maximize. So basically what
it's doing is it's accessing the Two-Sided Sign. And it's changing
some of the parameters like speculative opacity and
refraction on the bottom side, just to behave a little bit nicer. Because we're actually using the
Pixel Normal Offset refraction mode. You could use Index Of Refraction, but we found that,
for water, it just doesn't really work very well. Because refraction is
a screen space effect, you really need it
to stay on screen. So Pixel Normal Offset refraction still gives better
results, even though it's less correct, because it keeps
the refraction on screen. But it does mean you have to spend some time doing some little
corrections for the underside. So this just applies,
so far, waves, textures, and attributes. And then from here
on what we're doing is we're just adding
behavior as is needed. So river flow maps exist as
their own kind of function. The river material,
which is an instance of this one, just checks this box. So the ocean, by default, is not paying any
cost for the river. Beach foam is very similar. Here's another function
for beach foam, where by default it's bypassed. So there's nothing there. And it's not on by default. So you need to make a material
instance for ocean. So we see here there's
an ocean instance. If we look at this guy. By and large, all the settings are blank except for
Enable Ocean Foam. And the reason I like to
keep all of the parameters blank in most of
these is so that you can decide to use inheritance,
and then just change it at the top level without
having all the instances have different values. So beach foam-- now, notice that there's
this scattering pin which comes out. Because you can't
really add scattering to the water material
in the Water Attributes. And the reason for that is-- that's weird. It didn't want to go
back to the regular pin. Oh, I accidentally
turned off [INAUDIBLE]. Sorry. So scattering doesn't
exist down here. Scattering exists on the
single-layer water material node. So what that means is
if you want something to pass between both parts of
the material, regular shading and the scattering, you have to
pass them down to this branch down here. So here again is this
single layer water which we saw from this
[INAUDIBLE] before. And it has, like
before, our absorption, which I'm doing as the
length like I showed before. Scattering here is
basically also adding in scattering from the foam. So you'll see we
have another option. If there's no foam,
it just adds zero. If there is foam, it's going to add
the foam scattering mask times the foam value. So you get a little bit
more scattering wherever there's foam, which is nice. And then again,
this Water_Underside, again-- I mentioned this before-- it also has to affect the
scattering so we basically have scattering in, scattering out. And the reason why we want to
do that is because when we're above the water,
what it's actually doing is it's using the
length between the pixel under the water and the water
itself to determine that depth. And then it's kind of
fogging and coloring based on that depth. But if you go underwater,
if you don't mask that out, what would actually happen
is it would fog based on the distance to the sky. So you would just get like
solid blue above water. [COUGHS] Excuse me. I feel like I'm losing my voice. So we just set those values to
zero when you're underwater. And that's what lets you
still see through the ocean. And I'll talk about
post-processing later after this. It's a little bit busted here. But there are some solutions. OK, so we're almost done with
the basic water material. All right, so we got to the foam. Next we have another function
for fluid simulation. We'll be showing that
in a little bit as well. But this is a function that maps
the additional displacement and normal map that comes from
the optional fluid simulation. So that's how it's able to
get little ripples, and bullet impacts, and things like that. This WaterOpacityMaskFromDepth,
this one isn't actually really necessary. But what it's doing is it
makes the final material a mask shader. And we do that kind of
purely just for editor polish purposes. So you'll notice,
when I select this right now, you'll see the outline of
the water more or less. If I were to go
into this function, WaterOpacityMaskFromDepth,
and set this minimum water depth for the mask
thing to be really high, now I've disabled that function. So now we're seeing the
water in its raw glory. So as we looked at before with
these water tiles, where-- so these tiles aren't lying. The water actually
is just squares. and what we do is we use the
data of the water texture to mask out the parts
that aren't needed. And additionally, we set the absorption
and scattering to zero when we're not doing
the masking, so another way to do that is,
instead of masking using opacity, what you can do is mask-- just the way that this
is doing scattering here, you could also mask
using this water depth. And this is a good time to show-- throughout all of these functions, there are a couple functions that are kind of universal water
functions being used inside. And probably the most
common and important one is WaterBodyData. And what this function does is it returns all of the
water information from the water terrain system. So it has all of the relevant
things that you might need, such as the Water Velocity, the Water Z Height,
the Water Depth and the Water Depth Clamped. And that's important to
notice, that water depth can be negative,
which is useful in some cases. And then the Terrain Z Height. So because we know the
water depth by the texture, we can mask out that region. And I'll jump into another
example of how that Water Body function is used. Go to River Flowmaps. So this is still a relatively-- sorry. Having two-monitor troubles here. OK, so this is still a
relatively simple Flowmap function. And you'll see what we have
is the basic core for it again is WaterBodyData. As before, if we open
WaterBodyData, this function, under the hood, has reference
to this water velocity height, which is this global texture. And it has all this
global information about the landscape. And it knows basically how
to decode this data to get it and so that you can just
use it in world space. And pretty much all
of the materials that go through the water system
have access to these things. And if you were to look
at, say, you can go down, under
Debug, on a water body, and pull up its material
instance dynamic. And that'll give you
an idea of what's being set on the water body. So you see we're setting
the water body index, which doesn't technically need to be
done, because it's also getting it by the tile. But we're also setting it
because of some legacy stuff. This is the water
velocity and height, which is the texture that
comes from the terrain system. So I can go ahead
and look at it there. And that's being assigned to
all those rendering materials. And that's as you edit the water, you'll see that thing
change every so often. OK, so I feel like
we've done a decent job of showing the basic
setup of all this stuff. I don't know. Victor, you still following
along with me here? How are you feeling on this? Do you think that we've
showed the basic shader enough on this point? >>Victor: Yeah,
I think the material is good. And just to give you an
update, we've had pretty stable
quality throughout. Seen a couple of dips. But in general,
we've been able to see everything. So please continue. >>Ryan: All
right, so now that I've shown-- this is kind
of the master material which we would say it's a
good starting point from where you would start to add your more
game-specific functionality. We'll go ahead and look
in, a little bit, what are these different functions
for, say, the foam, and the fluid
sim, and the height map. Oh, I knew I missed
one-- height map. So just to really quick-- what we actually do is use
the Water Z Height here. And we can form the whole
mesh to the water height, and kind of neutralize
its base mesh position. So you can see here,
it takes water height and then it subtracts
absolute world position. So this means it doesn't matter
where the original verts were. It will end up just positioning
them to the right height. But this is also why
we have challenges in coding water
height, and dilating, and water bleeding above
edges, and things like that. There are some considerations
worth mentioning. But the reason it's necessary
is because we don't actually save the water geometry. This is actually-- as you can tell from looking at the
wireframe, it's instanced quads just
being used everywhere. It's not like this is
actually a high-res mesh. So we don't actually
store, anywhere, hey, the height of the
water right here is this. The only place we do store
it is in that texture. So we mapped as well. OK, so now we've showed more
or less most of the features for the really
basic terrain stuff. Yeah, I guess we could go ahead
and show some fluids and stuff. How are we going for time? Oh wow, we've already been
going here almost an hour. >>Victor: An hour. But this is great. So why don't we just continue
as long as you want to go. >>Ryan: All righty. So I've got a fluid
sim terrain map here. And we'll start with
kind of a simpler one, and then we'll build
it up from there. And this one here,
I've set the waves to be almost off so you
can see a little bit more clearly just the
detail normal texture. So as we're up close here, this is actually
that detail normal. In fact, let's go ahead and just-- You can turn that off if you want. But I keep it on there just
as a really subtle thing. I'm going to go ahead and turn
it off for now since we're looking at the fluid sim. And what we have here,
this is just the terrain with a lake and a river. And we have the fluid sim
actor, and then we have a couple forces that
are ready to do stuff. But I'll point out that-- this guy is turned off right now, so he won't do anything yet-- but when I press Simulate,
I've got an impulse over here. So this is set to do an impulse. Right now it's set to
do it every two seconds. And you can see we have
some settings for Radius, and Strength,
and things like that. So I can move it around. And I can also select
this skeletal mesh guy. And we'll go ahead
turn on his Strength. So now, as he's walking around,
he's making some ripples. And you'll notice
that the ripples are affecting the terrain as well. Although it looks like we've got
a little bit of a bug on here. Hang on. All right, so first let's
look at the actual settings for the fluid sim. So the fluid simulation
is, right now, this Blueprint that
lives in the world. The settings for it
are under Simulation. You can optionally show
the mesh just as a debug. But it's meant to just render
with the existing water. There are some different
modes for changing the solver. Right now,
it's in Shallow Water mode, which is much more experimental. Fortnite shipped using the
Ripple Solver version-- we'll show some differences
there in a little bit. But the main difference is
that ripple solvers do not use velocity. What they do is they
add some water height, and then simulate the
spreading of a wave from there. So all the waves kind of travel
at the same linear speed. But you can still get
some pretty nice results. So I'm setting it to
Ripple Solver now. And then I'm going to
go ahead and select this repeating force. And I'm going to
decrease the strength. It's worth pointing out that
the strength of the forces is pretty different
between the two Sims. And that's just a
factor of the fact that shallow water is
much more physical. It takes things like
terrain height into account. But you can see here-- this
is with shallow water-- it's fairly simple and
it's fairly robust. You can't really
break shallow water. Sorry,
let me restart that sentence. This is using the Ripple Solver. And the Ripple Solver
is fairly robust compared to the
Shallow Water Solver. And what I mean by that
is it doesn't matter how big of a force you put
inside of a ripple solver, it will never break down. Like even if we say
5,000, it's just going to look a little noisy. But it's never going to
completely break down. But whereas with shallow
water, it's much more advanced and it uses velocity. So it actually advects. And if the velocity
gets too high relative to the resolution or the time
step, it can kind of explode. But it looks a lot more realistic. So first I'll show a little
bit more with the ripple, because that's what
Fortnite is using. Go ahead and turn this
back down a little bit. So you see here we have
a movement component. The basic types of forces are --
there are impulse forces, which impulse forces are basically
just instantaneous trigger things. And I'll go ahead and show
the Blueprint for this. So basically you just call
this Apply Fluid Force Impulse on the sim. And there's this
Impulse Settings struct which defines all the
settings for the impulse. So first what we do is we
specify the actor location on the impulse. And then we pass it in. And you can change all
the impulse settings here in the defaults or in the world. So this is, for example,
how bullet impacts in Fortnite are done. Whenever a bullet weapon
traces against a water body, it just calls this Apply Fluid
Impulse at that hit location. And then you pass it in. So there's a couple of
cool things kind of built into that, though. There's also this
option down here, this Timed Water Drop
Splashes that you can enable, which we use in
Fortnite for the bullets as well, which kind of means,
after your initial impulse, you have a secondary effect
that, after a delay-- so here there's a 1 second offset. And this has a lag time of 3. We'll get these little raindrops. So first I'll play
it again with it off. I'm going to set Impulse
Every N Seconds to 0. So we're just going to
be looking at this thing when I press it. So now we press Trigger. Set that a little bit less. There we go. So now I'm going to check this
Enable Water Drops Effect. So after 1 second,
we should get a 3-second splash. But the splash is way too intense. So let's go to something-- There we go. We saw we got a
little raindrop there. And you reduce the
number of drops. There we go. It's going to be a
little more obvious. So effectively you can say
how dense of raindrops. So I'll lower that
down so we have less. And this should be a
little bit more obvious. Maybe reduce Strength even more. So that's just kind of a neat
way, when you have something like a bullet impulse,
you're probably going to have an effect
play that does a splash. And this lets you, say, time that splash so that it looks
like it causes fluid when it's really not. So you might want to say
make that much shorter. Maybe you're upset because
it's a really short lifetime. I don't like how that's looking. There we go. So you can do quite
a lot with this. So before the impulse
types, this is Impulse, then there are Dynamic Forces,
which this skeletal mesh guy is an example. And if you go to-- I feel like I should
have led with this, but where we're working out
of is in the Water plugin. So the various different
categories here-- we tried to break it down-- fluid simulation is mostly
under FluidSimulation, materials are mostly
under WaterSurface, so all the water material
stuff we looked at prior. We're going to go to
FluidSimulation right now. Under Blueprints, this is where the
main fluid sim is. Under Examples-- this is
everything we're looking at right now-- it has an example for the
impulse, the mesh, and the dynamic force. So the main difference
between these things are a dynamic force
can actually calculate some vectors based off of
something like a skeleton. Let me close down these
windows real quick. Here we go. OK, so these are examples
of the dynamic fluid force. And you'll notice here
that, on Force Type, you can choose different options. There is Component Location and
there's Skeletal Mesh Sockets. So these are both
actually the same class. It's just that the
Component-only one is set to just be component-only. In fact, in this other Blueprint, I'm just making a
fluid force dynamic and setting it to
Component directly, and then just setting
all these things. So they're just
different Blueprints of this same type of example,
but just different types. But we could, for example,
on this skeletal mesh one, set it to use Component Location. Or we should be able to. Oh, you know what? I think we're not calling-- that didn't work. That should, in theory, work. It needs to have really low-- >>Victor: Live
demonstration, everyone. >>Ryan: All right,
so one thing that's making this pretty
noisy right here-- we're going to go ahead and look
at the material for the force. So that's how this works is you
specify the type, the radius. And then, for skeletal mesh,
what it uses is these sockets. So these socket
mappings actually just use sockets on the mesh. Going to go ahead and select the
mesh, just to show those. Character > Bones > Sockets. There we go. So these are the
sockets that I'm using. Basically it's like
a stick figure. We just have kind of
feet, to shins, to pelvis. Or actually not even pelvis. We connect the knees
up to the spine. So we basically just draw a
really basic stick figure guy. A cool way to show this could be--
here, let me do this. And I will set him
to use no animation. OK, so now I'm going to simulate. And going to open up his material. So the reason that it's
actually getting so noisy is because we're
actually doing collisions on the skeletal mesh. I'm going to turn
that off for a second. So now we're just
getting the motion. So we can actually look at that
too, and see the stick figure. So I'm going to
select the Fluid Sim. I'm going to go under
Debug, Forces. And I showed this a little
bit during my Unreal Fest presentation. This guy is so tiny. I don't know if you guys can see, but there's a little stick guy. That is our guy. Let's make it a lot bigger. So the reason it's
not always showing is because we're really
adding a velocity force. So sometimes it's negative. But you can see kind of
the stick figure shape that we derive from. Although it is worth pointing out, whether or not you have
collisions enabled really depends on what your
intended behavior is. So I'm going to go ahead
and turn that collision back on in here,
which is just whether or not you output the alpha channel. And the way that
this works is these are actually rendering
these capsules. And it's passing in the
socket points to the force. So you'll see, now that I have the
collision back on, when we have the impulse,
you actually get the-- let me increase the radius-- We actually get the ripples
bouncing off of the character. It's a little bit more
obvious when I make it-- so he's now acting as an obstacle. See that? When the wave gets there,
it bounces back off. And that's purely because
of setting that there. We can do the same thing
for this component one. We can click on his material. And currently it's set
to not have an opacity. We have this mask
here we can apply. Go ahead and do that now. I need to set the blend
mode to Alpha Composite. Bear with me. There we go. So you see you have choices, when you're defining the
obstacles for these guys, how you want them to behave. All right,
so that is the Ripple Solver. And it's also-- let's
also really quick show the river velocity. So I don't think I have
a velocity here yet. But we'll go ahead and
select these points. And we'll say-- there we go. And also there's no guarantee
that velocity is always downhill. So in this case, it's negative. It's based on the orientation
of the actual spline. So it could be
negative or positive. Now, if I put that-- actually,
I'm not going to put that. I'm going to to put the impulse-- so we should see the impulse
get advected downstream as well. A little bit too fast. So you control that velocity. So now we might
want to reduce that. And it's also controllable
in the sim as well. It's probably set a little high. I feel a crash. No, we lucked out. Just reducing these down. I think we just had that
value set to be something that was for Fortnite. So notice that we still have
the appearance of water flowing downhill, even though what
we're really doing is simulating this
all in a flat space. So the Ripple Solver doesn't have a concept of terrain
height but it does have a concept of terrain edge. So when a ripple hits the
terrain, it will reflect. That's more noticeable when
we turn down dampening. Let's go ahead and
increase travel speed. And we'll set damping to zero for
now, even though it's going to go a little crazy. So without damping, you'll see
much more obvious reflections. So the reason you want
damping, obviously, is this is just going to
bounce, and bounce, and bounce, pretty much forever,
and just get crazier. Let me go ahead and set
-- I had it at 0.01. We might want just a little bit. And damping acts very
differently with shallow water, just to mention. So now you see just a
little bit of dampening, the ripples have
faded a little bit by the time they get
to the other side. But they still have
some persistence. So this is basically the
configuration for the fluids that we use in Fortnite right now. And then the main
difference being, for that foam
channel-- and I don't know if you saw, a moment
ago, I had the foam. Let's go ahead and turn that back
on, add a force component. Did I lose it? There we go. We're adding back this
force component again. So he goes a little bit crazy. So I typically turn
off the collisions for the dynamic objects,
just because they're not that important that
they reflect waves. And it gives you a
little bit more stable, especially once you
turn down the strength. But I can go in here as
well and add some foam. So right now we have the
foam being set at zero. Let's crank that up. And that's going to
the green channel. And that should-- let's
see if that works. You know what,
I might not have the right foam material enabled here. Oh well,
we'll go ahead and skip that. So now I'm going to go
ahead and switch this over to shallow water,
just to show the contrast there. So shallow water is
more experimental, and I would say definitely a
lot harder to get it to behave. And there's also a Niagara
shallow water plugin going to be coming out soon as well. So we will eventually be
supporting that as well. But for now we're taking a
look at just the shallow water inside the Fluid Sim. So you see, here,
we have Ripple Solver. We'll set Shallow Water instead. And right now we're
mapping to the whole fluid, just because we set the
size to be the same. But this all works when
we set the size smaller. But I'm just going to keep it
to the full terrain for now. OK, so we set Shallow Water. But now what matters
is, under Shallow Water, whether or not we are
using Constant Water Depth, Terrain Water Depth Only,
or Terrain with Elevation. So that's actually an important
thing to talk about real quick, is that it depends on
what your goals are. So in Fortnite,
we actually wouldn't want to use shallow
water with elevation because what ends up happening is, if you have a river that's uphill, that river will
just drain downhill. And you'll end up flooding
some valley or your rivers will run dry. And we'll go ahead and
see if that works here. Let me make sure the rest
of the settings are OK. So dampening might need
to be a little bit higher. So you see what's happening here is that that river is actually
flowing downhill into the lake. You see it's actually
going pretty slow. So let's see,
let's make it go a little faster. So that's what happens if
you have a time step too small with shallow water. That's what I talked about,
when it's not quite as stable as the Ripple Solver. Generally, when that
happens, the only option is to either increase
the time step or increase the density,
or sorry, the dampening, not the density. Let me see what is happening here. Not getting the fast flow
that I was seeing earlier. Let me load this
other test map I have. OK, so this is a different
shallow water map. Should be very similar. But I've set this one
to have some waves and to have a
different material that attempts to simulate the
Gerstner waves on the shore. So of course this one did flow
downhill a little bit better. So this is kind of an attempt at, wherever a Gerstner wave
gets to a certain height, we add a little bit of force
into the shallow water sim. And then that causes the waves
to kind of lap up and down the shore. Although this is kind
of in a state of flux in terms of getting
it to blend nicely. And there's some issues with
the waves causing it to clip. I ended up kind of breaking
that in this map when I fixed it for the smaller-scale wave
foam splashing example, which we will show you
in a little bit as well. Yeah, that's weird. I'm not getting--
what we should be seeing is that the
river essentially empties into the terrain when
we set it to Shallow Water. Let me try that one more time. Maybe I just needed
to reload the map. Shallow water. Oh, you know what? I think it could be this-- OK, I think I remember what it is. There's this dampening option. Let me set the advect. Bear with me one second. >>Victor: It's
really exciting so far. >>Ryan: All right,
I believe I figured it out. There we go. Yeah,
so I had a parameter in there that was basically fading back
the water to its default state to try to prevent it
from losing volume. So this is another big
problem with shallow water. When I take that
off, this water is going to kind of lose
volume over time. So it's adding maximum velocity. Sorry, it's eventually
just going to drain. So this is that
advection material. And right now I have this
Fading Back parameter. And what that does
is it kind of always fades back to the default
state of the water so that it doesn't
ever fully empty. And based on how strong
you have that set, it will kind of determine how
much this thing is stable. But yeah,
it takes a lot of work to try to get the fluid to be completely stable with shallow water. So yeah, generally,
smaller time steps and reducing the forces all help. Let's go ahead and-- the dampening of 0.01 is way
too small for shallow water. You need at least, like, 1. All right, so these other forces-- let's go ahead and turn on some
forces with the shallow water as well. So you see the effect--
oh there we go. The foam's working there. Seemed like it wasn't
adjusting the strength. There we go. So yeah,
depending on your resolution, you really might need to fiddle
around a little bit with things like the strength of your
forces and the dampening of your field. Because it just really
depends on a lot of factors. There we go. We got one. It was a little bit too much. And generally we'll
clamp the forces and clamp the time
step to prevent that. So it should be a little
bit more robust than that when it actually ships. But yeah, you can make cool boat
wakes, cause explosions. And now, just as an example,
I can set the dampening quite a bit higher. That can go above 1. And that will make
it a lot more stable. Still not entirely,
but here we go. All right, so I feel like
that gives a decent context on the simulator. But now I'll go ahead and show
that other example, which was using the Scene Capture mode. My fingers crossed, because I've
been changing a lot of things. This might break for me. But basically the difference here is everything is the
same except we're simulating a much smaller area.
I've set it to show the mesh here just to debug. It's set to 2048,
which is about 20 meters long. That's about like 10 people laying on their side,
11 people, if you're struggling for scale context. The resolution is 512. And you'll see here,
under Shallow Water, we're using this
different mode here, called Use Scene Capture Depth. And with this mode, it's actually using
a scene capture to make a capture of the
scene, including things like static meshes. So this is definitely much more
on the experimental spectrum, versus the terrain
stuff works with what's already available and baked off. So there's no more memory
overhead or complexity. But with the scene capture,
you have to be aware, can you afford that render
target and that capture on load, as well as if this
simulation needs to move, you might need to
recapture the depth. So it's really great right
now for testing a really high-fidelity small-scale sim. I'm going to go ahead
and turn on the sim. It's actually not on right now. So you'll see there's
some Niagara particles. I'll hide them. So this is what you
get if you do nothing. You have waves,
and they just kind of lap through. It doesn't look too bad,
but you don't really get that feeling of interaction. So what's actually being done
here to cause interaction? I'll turn on the sim now. And at first, it won't have the
Niagara particles contributing. Hang on a second. I don't think-- there we go. I had to refresh something. Apologies. So what this is doing is
it's the same shallow water sim we saw in the last map. And it's the same
basic concept where you saw I was using the waves
to kind of add on the shore. It's just this has been
refined a little bit more. The way that this is being done
is, on the fluid sim actor, there's actually components
for a few different things. And they're all kind of separate. Let me pause this,
because it's distracting. So right now, the shallow water
sim is a separate component. And that's useful because it
allows you to kind of build the solver as more of a
standalone thing that doesn't bloat up the main Blueprint. And that's where it has the
actual MIDs that it needs, and the additional
render targets that do not have to belong
to the rest of the sim. So like velocity and the height
ping pong all exists over here. Sorry, total brain fart. Oh yeah,
but it's also a great place to be able to do kind
of specific overrides. So you'll notice that
while this is mostly just debug-level stuff
at the component level, because you're setting
most of the simulation settings in the main
Blueprint under shallow water. And kind of what it does,
when it initializes, it just passes what it needs. But there's a few other
things inside the component that you can override
that are not exposed. Like for example here,
this manual advect material, it's basically replacing the
advect step with a custom advection material. And the advections
step for the fluid is basically where it pushes
and moves the fluid around. So it's kind of a
generic place where you can add more fluid as well. So inside of this material,
which I'll load up real quick, this left part,
this is the base advect that everything else will do. And everything else that's in here is basically fluid
foam experiment stuff. So I'll go ahead and show what
that looks like over here. The way that that
actually works is we have another texture called
this foam render target. And this contains
some useful detail that other systems can use. So this is actually a system
that is rendering out foam for wave crests that we
haven't actually shown yet. But I will show that in a bit. So we get this nice
foam history you can see there as we simulate. Let me go ahead and show that. Looks cooler on the
actual ocean of course. But we do this cool time
history generation of wave caps. But then that shader
also kind of renders out the Gerstner wave height so
that another place can look up the Gerstner waves without all
the complexity of computing them again, which is handy. So inside here, what we're doing
inside the fluid sim, reading that wave height. And also, remember WaterBodyData, that function that I
mentioned previously? We're reading the water body
data inside of the actual fluid sim in a render target as well. So the only real difference
to use it there-- again, you need to make sure
that the texture is bound. And then there's this function, Fluidsim_RenderTargetWorldPosition So this basically just
takes the implicit UV and converts it to
a world position. So basically where in the
world was this render target. And then it knows how
to look up the data. So basically by using that
combined with the scene capture depth, we're able to figure
out, hey, where was the water
over the rocks? So we take water z-height. We add the wave height. We subtract the scene depth. So right here,
this little expression is basically how high is
the water over the rocks. So then, using that-- in a couple places,
it goes down here and it adds fluid to
the sim using a max. So it's basically any time
water is going over the sim, it will do a max with a
little bit of the wave water. So it's kind of like,
as a wave travels over the water, it just leaves some
of itself behind. And I'll disable the rest
of this stuff for now to show it more obviously. There's some foam injection
based on velocity. And there's some foam injection
based on a narrow band right at the intersection. So now, all that's off. So all we have is
we're fading the foam and then we are adding the
foam, edge foam as well. So some of this
complex stuff over here isn't really needed in
this custom material. It's just kind of some
stuff that allows the system to automatically detect if
it's not been initialized yet. Because we initialize it with
this really negative color. So if there is this negative
color present in the render target, what it does is it
grabs the water body data-- so this is how it seeds the
fluid sim with all the water data in the world. But the way that that
seed works is different depending on whether you're using the terrain with elevation or
the terrain with depth only, or with the scene capture mode. So basically it looks complicated, but it's just some
switches that kind of do a different mode of
initializing depending on which mode of fluid sim you're doing. So what I did just a minute ago is I set it so that all we're
doing is adding fluid based on the wave. So you'll see now-- notice, when the wave goes,
it sticks behind a little bit. And I'll go over to
that parameter directly, this Fluid Per Frame thing. Set that to zero. So when that's zero,
once all this fluid falls, it's not coming back. Does that kind of make sense? This is just like the raw fluid. If I set that to 1,
that's too much, it's like there is always the
maximum wave height, instantly. And you can see it builds up,
and then it flows back down. You can even cheat in here and
say, oh, we want to make the waves taller. So they go up a little bit more. So when we do this,
this is really just causing them to flow downhill
nicely, but it's not really giving it that punchy reaction. So the way to get
that punchy reaction is we also identify this
band, which this right here is kind of like building a sphere
mask near that water-rock edge. And then what we do is we
multiply it by another value and we call that the Fluid
Addition Above Rocks. I'm going to set the
other one to zero. So then we'll just
do the edge one. And it'll be really obvious. And this one can be a
little bit more aggressive. So I had to do like 75,
but we'll set it to 100. So now,
wherever the fluid first hits, we get more of like a quick,
high, little water edge. We'll make that much higher. There we go. So now you kind of see,
when the water goes up, it's actually kind of
overshooting and causing the shallow water to shoot up
over the rock a little bit. And then that causes an
impulse which then spreads it back down further. So this is what I say-- this is really a mixture of
an analytical technique, which is Gerstner waves are considered
analytical because you say, hey, I have a time and a position, and I just get a value. Whereas shallow water
is not analytical. It's more, I guess,
time integrated. So to have them work
together, you kind of have to have some rule for how
does the Gerstner waves feed in its inputs to the system. And it's never quite perfect
because it doesn't actually affect the Gerstner wave
the way that it should. But there's actually
some cool things that we can do to make
that happen as well. But that ends up being kind
of on the material side. So I'll go ahead and jump
back to the main material. So this material
in this scene here is a little bit different
version of the water material. I made an _Beach version just so that I can do some
stuff for this scene that's a little different. All right, where is the fluid sim? OK, yeah,
WaveDistanceFieldReaction. There it is. Sorry,
I was having trouble remembering where I had moved this thing. There's this other
little utility function. It's down under the kind
of general water functions area, where you see we've got a
bunch of neat little functions here, like Wetness,
WaveDistanceFieldReaction, DepthFalloff. These are all the utilities that
you really need to use water. WaveDistanceFieldReaction
is kind of interesting. What it does is it attempts
to modify the world position offset of
the Gerstner waves to kind of do a little bit of
a reaction against the scene distance field. Currently it's being set to
act on this distance field in a texture,
which I mentioned before that this simulation here
is actually using a scene capture to capture the rock. While it does that,
it goes ahead and also generates a custom distance
field, just because why not? You already have
this texture here. So green, this is the height,
but red is the distance field. And to do that, it's using that
component that was mentioned. So just for the sake of
completeness, I'll show it. I don't know why,
but I'm having a clumsy mouse day. OK, wrong fluid sim again. >>Victor: Doing a
good job on the one-monitor presentation though. >>Ryan: Thank you, sir. All right, so I mentioned
before, we have this component. There's this
JumpFlood_Component2D. This is actually from
Landmass as well. And it's actually the
same thing that the water rushes kind of use under the
hood to generate themselves. But this Jump Flood
Component is able to take an input of a scene
depth, and then output out a distance field. So what we do with that is
we generate a distance field of two masks. So you'll notice that we have
here world sim size is 2048. But then we also have
this wave simulation. That's the foam spreading
that was mentioned. But usually you want to
do that at a bigger scale, because it holds up at lower res. And you want to see foam further. So you want to kind of
spread the wave simulation to a larger area. But for that same wave
sim, you might want to have access to that
distance field as well. And just a quick note
that, whenever I'm talking about this
distance field texture, you could also use global
scene distance fields. The main reason I was using
the texture here is because a) I already had that texture
resource because of the height. And I wasn't really getting
good results with the scene global distance field
because some of these are Quixel rocks
that are not capped. So they have to be two-sided
distance field generation. And that just doesn't really
give you a very accurate true inside value. So I'll just make
this distance field from the actual height map. And then we have it. So if I look at
this texture again, looking at the different channels, you see we actually have two
different distance fields and two height maps. So red/green is the fluid sim
one, and then blue/alpha is actually the wave one. So I don't know if you can
tell, here, this one is actually much bigger. And it's including
this little clip of the corner of the terrain
there, which is this white bit. So that's pretty handy. I'm making use of that
inside of Niagara, and all these materials,
to kind of integrate that better. But that was kind of a
very verbose way of saying, this is just a slightly more
high-quality distance field that would work just like-- this is the global one,
get DistanceToNearestSurface. And it kind of works off of
the global scene depth one-- or not scene depth, but the global mesh
distance field, which you see here. So-- also works. But what we were
originally talking about was this
WaveDistanceFieldReaction. What I'm going to do real
quick is pause this wave sim at a certain spot where there's
a wave kind of over the rock. Let me just wait for one. [SIGHS] Whenever you want a
wave, it's never there. And then there are always too
many when you don't want them. Come on, wave. >>Victor: Turned into
a little mini game now. >>Ryan: I know. Waiting for-- catch the wave. Here we go. So going back here to this
WaveDistanceFieldReaction function,
we extract a band from the mask, and we take the original
world position offset, but we boost it by
a certain amount. So that's interesting. Ah, let me make this-- Actually have a
slight problem here. But I can fix it by-- just reading the
wrong color channel. Let me really quickly set the
simulation sizes to match. And that will fix it. There we go. So that fixed it. And now we see the
giant distance field wave reaction thing. There we go. So it's basically
just really pushing up that wave whenever
it's near an object. And if we unpause-- it's not always perfect,
but it kind of gives it just this little extra oomph
of a push when it finally does get over there. And if I turn it off,
you'll see it just kind of feels something's missing. And then there's one other
thing that can be done. It's already being done,
but it can be turned up. Let's crawl all the way back here. You'll notice I
actually already am using the DistanceToNearestSurface
with this DF Lag value. And what we do is we feed it
into this ComputeGerstnerWaves function as a time offset. So GetWaterTime is just
the universal function for water time that lets you
freeze time and control it. But it doesn't have to be used. But it's nice because
it lets us have matching time across
the board and all these different effects. But what I'm going to do now is
open up the material instance and look at that lag value. So lag is set to 0.3 right now-- or negative 0.3. And what that's actually doing
is pushing the wave back, away from the rock. If I set it to 0, you'll see it it's
right up with it. If we go negative 1,
can you kind of see-- it might help to-- you know what, let me-- here we go. I feel like I should disable
the sim really quick. Yeah, I'm going to do that. Where is the advection? I'm going to set this
to 0 and this to 0. Just because I feel
like it was disrupting-- showing the lag. So can you see the lag there now? I'll load that material back up. What I really want to do is
pause this when it gets to-- there we go. So we pause the wave when it's
kind of right on a rock now. What we do when we apply the lag, you see, we're kind of
pushing it back in time so that it's happened a little
sooner or a little later. We can push the other
direction as well, but it wouldn't really make sense. So like if I pushed forward one
second, you'll see, when a wave gets near a rock,
it kind of like telegraphs there. Whereas when it's at 0,
then it just matches. Now I'll slowly drag it negative. Yeah, if you go really negative,
like negative 10 or negative 5, you actually go back in
time through all those wave states near the object. So that's not a good idea. You need to keep it probably
between like negative-- small values. But I don't know,
it's a subtle effect, but it's the type of thing
where, if you turn it off, it's more noticeable that
it's not there then when it is there, especially once you
add in the Niagara particles. So those are those
particles there. But they're not actually being
fully leveraged just yet. But before we do
that, let's turn off some of this other
stuff, because we've gotten a little bit crazy. Just going to set this Distance
Field Direction way back down. And notice that we've
turned off pretty much all the foam and all
the water interactions. So now we just have
the wave lapping, and then those particles
are just there. But if we want to turn on
the particle interaction, right now, that's actually
happening as part of Niagara using a new experimental feature. All we have to do to
enable it is select this from this ticker. And this right here is just
kind of an actor that's designed to tick in the editor. This all can be done without that. It's just I'm in dev rendering,
where there's some stability issues when you stop simulate
mode, sometimes crashing. So I'm doing this without that. But now that I have that
Niagara grid enabled there, notice we get foam again. But it's only coming from the
Niagara particles themselves. And the way that
that's happening-- so this is actually a
nice tie back to the start of this stream, when we talked
about the fluid sim, the impulse force. So the way that this Niagara
fluid sim communicates back into the fluid sim is
actually pretty simple. It's just applying an
impulse, just like a bullet. So you'll see down
here that there's this Fluidsim Forces Material. What that's doing is it's
reading the grid from Niagara. So let's go ahead and
show that real quick. So when I simulate, you see this little
mask down here? This is a mask of where all
the Niagara particles are splashing against something. And then, in this material, we're reading that and then applying it to the red channel
as a fluid force. And then we're adding it to the
green channel as a foam force. So we can actually
control those separately and see how it looks without,
say, foam from Niagara. So let's set Foam Fill to
0, Foam to 0. So now we just have
Niagara just adding water. And then if we were to
turn off everything, now that's everything off. We'll set water to 10. It'll be really obvious. Now, wherever we get a
particle, we get big, giant amounts of water. So now we can go ahead-- let's turn foam back
on a little bit. And notice what I'm
doing with this foam. I'm just kind of applying a
noisy mask with the tiling texture inside this
material just to do that, just to break it up. There we go. So if we look at that
foam texture again-- we'll look at that fluid forces
again, on the fluid sim. We'll go ahead and
look at Forces RT. So here now we can see
how that Niagara texture is being injected
into the fluid sim, just like we saw before
with our T-pose guy. But this is a little
bit more obvious now because we don't have the
scale and velocity issue. But you can see here, controlling the amount of contrast and offset in the foam with some
of these parameters-- so you say, oh, we really just
want little blots of foam. So the foam does diffuse,
which is why it kind of blurs out really quick. But we can go in there
and disable that. So if you see in here,
see all these offset samples, this is actually just
sampling the height texture next to the neighbors,
and just averaging it. What we can do is skip that.
Let me just delete it for now. So you see here,
what we're really just doing is we're just adding the
existing Height foam channel to the Forces foam channel. Go ahead and compile that. So now we have no
diffusion on the foam. So it might look less foamy,
but it will also be more-- you'll see the exact
detail shape of the-- it's more obvious when
it's first adding, because it kind of
stomps over itself. You can kind of see how it has
that modeled pattern in the foam. Can you kind of tell, Victor? >>Victor: Yeah,
it's coming through. >>Ryan: So yeah,
that model pattern, just basically from the texture. But this Blueprint that's
actually providing this, this is something that you
wouldn't need in the long run to pass this in. This is just-- because of
the experimental nature of the Niagara feature
that it's using, called Shader Stages,
it's using this to basically get a reference to, and copy that
render target from Niagara out. But let's go ahead and just
I'll show that Niagara system, just because it's not that crazy
and it might be interesting. So here we go. So here's the whole system. Like I said, it's actually a
pretty basic system that's really just like-- it's really just spawning
velocity in a cone. And it has a sphere location. And then it's doing
something called rejection masking,
where you kill particles that don't fit your condition. And in this case,
the condition is the water has to be higher than where the
terrain is and the water level has to be currently increasing. So using that,
it can basically mask out particles that don't fit that. So let's see what it looks
like when we disable that, just for fun. So let me go ahead and
set this Wave Threshold. That basically means
water has to be increasing by 2.5 centimeters
in the current frame to be considered a splash event. We'll set that to like negative
64 so everything's a splash. And then this particle
Distance Field Threshold, we'll just set that to like 512. Something's still not right. There we go. So now it's kind of always going. The reason it looks weird is
because it's reading that wave height texture-- or sorry, it's calculating the
Gerstner waves to match them. And I'll show what that looks
like in a moment as well. That's weird. It should be much more consistent. I'm not sure why-- oh, you know what,
it's because of the water height threshold in here. So in here, this function
looks a little bit messy. But really what it's
doing is it's just taking some conditions to
say, like, is the rock higher
than the water level, and uses some logic conditions. And really what it's doing is,
if the condition isn't met, it sets lifetime to zero. Otherwise it sets it to
the original lifetime. So pretty much it's just
particles continue on as normal until they're ready. Or rather they'll
keep trying to respond until the condition meets them. The reason why-- OK, yeah, it's only happening
when the water level is higher. So I can, say, check that box. And that should make
them all respond. No. Well, I'm missing something there. But oh well. Let me just show a video of that. I had a video of this
effect in a different state. Give me one moment here. There we go. So this is what I was
trying to make this do. But I guess I missed some bug. In this state here,
I set these particles just to always go but to be
much smaller, so that it's just more obvious that the
actual particle is being fed into the system. And yeah,
obviously it works better when you're thresholding
the spawning based off of the waves and when you're
trying to set the size and velocity as well. But hopefully that makes
it a little bit more obvious what's happening. So now let me see-- trying to think if we-- probably a good chance
to go through some caustics now at this point. Do we have some time?
It's a two-hour stream. That's good. >>Victor: I do want to
cover some of the questions. We received a couple of
good questions as well. >>Ryan: OK. Maybe if you want to
just start throwing me some quick questions. And we can transition over. Is there anything-- I'm assuming it's about
stuff that was shown. >>Victor: Yes. And there's some general
questions about the features as well. >>Ryan: Sure. Yeah, I'll load up the beach map. This is not a finished,
pretty map or anything. But it's kind of a little fun
example map about water foam. Then I'll show waves,
and lots of rivers, and some cool, fun little painted graphs and flattened out sand. >>Victor: It looks nice. >>Ryan: All right, go ahead. >>Victor: Yeah,
so in general, there were a couple of
questions in regards to if it's possible
to use swimmable so that your character
can use the swim movement mode in the movement
component automatically when it reaches the water. Or do you need to
work around placing specific volumes for that? >>Ryan: No. That's all handled by the
gameplay interaction system. So the one I mentioned before,
when we did that strike team for the Fortnite water, there was a couple general
engine/gameplay engineers as part of that. For example, Zak Middleton, who is kind of the guy who
generally sets up a lot of the low-level
player controller, and movement component,
and stuff like that. So you shouldn't really have
to do anything custom there. >>Victor: Let's see. >>Ryan: And there's
also the Blueprint node, which it's not yet in this
build, but in Fortnite, what you basically do, if you know you're
overlapping a water body, you basically
query that water body and give it a location. And then it tells you its wave
height and velocity, if any, and all that stuff,
and normal so Blueprints can use it for alignment. >>Victor: Is it possible to
move the water bodies at runtime? >>Ryan: Not currently. So what happens is
we showed before how, in the landscape, you get this Edit Layers. So kind of, as a general rule,
all edit layers, what they do is they get collapsed
on serialize. So that means,
when you save the asset to disk, all this gets combined back
down to just one regular set of height and weight maps. So that's for performance
and memory reasons. Because we can't
really just afford to bloat up the size
of the landscape by however many layers it has. But that's still a
really exciting area of research and something that
people ask about constantly. Especially even on the Fortnite
creative team, they're like, why can't we use this
in Creative mode yet? And yeah, so believe me,
we definitely hear you. It's just a matter of,
right now, all this stuff is fairly GPU-intensive. And some of it is kind of hard
to include as part of a cook process if that makes sense. >>Victor: How does the water
sort with other transparencies? For example,
how do you keep splashes from only drawing on top
or below the water plane instead of being cut
off as they intersect? >>Ryan: So that is just
currently a hard limitation with the single-layer water. There's no translucency
under the water. We tried some modes
that allowed it to work. But there was just a lot of issues because you no longer have
a correct depth to fog. So that translucent
thing would look like if it was fogged from
the distance behind it. So we found it was best to not
allow translucency underwater. So for any effects where
you need to show something under water,
what we do is generally do like a masked effect, like an emissive
bubble or something like that. >>Victor: Does
it support ray tracing? >>Ryan: Currently no,
but eventually it should. >>Victor: Can you
control the tessellation amount of the water meshes? >>Ryan: Absolutely. I knew I was
forgetting some stuff. So let's select the water mesh. Ah, what is wrong with me today? All right, so we've got
our water mesh selected. We're looking at Wireframe. Let's hide Landscape. There we go. So what we're looking at
here is the water mesh actor. And we can change the number
of tessellations of course. I had it at kind of the highest
setting it can go to right now. So this is progressive, obviously, to where it reduces in distance. You can also change the tile size. Right now it's not
quite working correctly. When you decrease the tile
size, it's reducing resolution. Kevin is working on that. And also, currently, you cannot go over
7 or it will kind of break. Let's see if we feel lucky. I'll show you what it does. It will hitch-- yeah, there we go. So the reason this
happens is because it's using a 16-bit index buffer. And I think it's overflowing it. So he's adding the option to
use a 32-bit index buffer. And then you can go really crazy. But yeah, absolutely,
you can change-- there's LOD scale,
which is per platform usually. So you definitely
have to make sure you keep an eye on how your
water features are working on different platforms, because it can be tricky to make it work
correct on all platforms given that we're using that
global water height texture. So it does take some tuning. I'll go ahead and show
that foam sim thing. I didn't show that yet. So here's the same thing. So in this case here, this isn't doing
the full fluid sim. This is just doing the wave-- or sorry, the wave foam. So you see here,
I'll select the fluid sim. Go down to-- was there
more questions or anything, Victor, while I'm setting
this up real quick? >>Victor: Oh,
yeah, we got several. >>Ryan: So down
under Wave Simulation, there's this Fading. So if I set Fading to
0, it does reset. But this will basically-- it will only be diffusing,
it won't be fading. But you'll see,
it will eventually just kind of fill up with foam everywhere. Versus if we set it to
0.5, it's going to be a really aggressive fade. I think I had it at like
0.2, maybe 0.1 or something like that. But it can give it a nice feel. And then so by doing that combined with a little bit of standard
distance field masking, you can kind of get a decent base, where it kind of feels like
these rocks are reacting to the foam, and it feels like
there's something going on even though there's really not much. But then this is a
really great base. Once you start adding a
few splash effects that are timed on top of
this, it's surprising what the human mind and eye
will do to kind of make it work. And you will kind of
visualize the interaction even if it's not there. So I'm pretty excited about this
combination of diffused wave foam plus separate
simulation foam being combined in one thing. I think it's going to still
take continued research to figure out the best
way to push this stuff. But I'm really curious to
see what people come up with. >>Victor: So there was a question in regards
to transferring between underwater to above. And they called those just
""that nasty jump,"" if it's possible to reduce that. >>Ryan: So yeah,
there's just a bug in here right now where it's
not matching the waves. And I'm not sure why. I think it's only happening
because of the steepness. So there's two different
post-process methods. Let me adjust the
waves really quick. So in Fortnite, we actually don't
use much steepness on the waves. For the ocean,
we use no steepness, which I'll show what that looks like. So this is an ocean
with no steepness. You see the waves are
much more sinusoidal. They're round. They're not sharp. But it reduces the
horizontal sloshing. Because as you do steepness,
you get this horizontal sloshing, which that caused some issues
with players feeling a little bit like they were swimming
against the tide when they really weren't. And it causes other
issues with alignment. So we set that to 0. So when that's set to 0,
the post process will match. It's actually that steepness
that's actually the issue. But if you do want
steepness, there's a separate post-process solution
that does not use the volume. So I can go ahead and-- that setting exists just under
Water, I believe, Rendering. So there is this Underwater
Post Process Material. We'll go ahead and
set that to None. And I think that clears it. So then there is this
other post process. It's a mesh-based solution. Let me add this to the world. The only thing is, right now, you need to get a reference to the
water texture for it to match. Of course watch it not work. Hang on. I haven't looked at
this thing in a while. So yeah, the reason it's not
working-- let me fix this. So really quick,
I'll give a theory of what this version does. So what our regular post-process
does that Fortnite uses is, per pixel, it actually computes
the Gerstner wave height, and then masks against
the screen on that. But that's actually
pretty expensive because you compute the waves
for every single post-process pixel. But what the mesh-based
version does instead is use a vertex shader and solve
the waves on that sparse vertex shader to kind of
reduce the complexity. But the only problem is it's
using the old Gerstner wave function before Kevin
did his buffer change. I should just be able to
switch this to the compute. And it should work. And then I think depth
attenuation should be fine. Let's try that. There we go. So now we get matching waves
with the mesh post process. And we can even go ahead
and set the steepness back and watch as I hold my breath. OK. Oh yeah,
I am having trouble selecting. OK, so now we will go back to
Wave, Steepness. So now we've got a
pretty good match. The only mismatch
comes now from the fact that the post-process
mesh actually has a lot more tessellation
than the water mesh when you get this close to it. So it's hard to get
a perfect match, but it's pretty darn good. And when the waves get
steeper than vertical, it cannot resolve that. You know what, let me do this. There's actually a
freeze time in here. By the way, this Gerstner wave
controller thing, this is going away completely. It's purely there right
now just as a debug tool. So you can see we're
matching pretty good. Let me go try to find a
really, really steep spot. Yeah, here we go. So it can't match these
over-vertical steepness areas. So there might be a little
bit of a discrepancy there. And that's just kind
of a limitation. But I think, in motion,
and once there's effects, you don't really notice it. But yeah, hopefully that
answers the question. >>Victor: They're
all curious what hardware you're running right now. >>Ryan: So I just have a-- what is it called-- 2080ti >>Victor: OK. >>Ryan:
Something wrong here. Oh, you know what, I'm seeing
the mesh and the post process. So there's something
going on there. But yeah, we're still in
a heavy bug-fixing phase, as I mentioned, because of the
integration to Fortnite. So quite a few of my-- I'm surprised things are working
as well as they have today. Yeah, I'll go ahead
and do one more thing. I'll set the caustics on here. Rendering,
and let me go find my ocean. >>Victor: Is there
any way to transition from translucent
water to an opaque shader at a distance for
optimization purposes? >>Ryan: So, you can do whatever
you want there. I wouldn't do that,
though, because you're not going to match scattering. What we do instead
is, on the water mesh, there's this thing
called the far mesh. And what that does is it
lets you specify a simpler material in a simple mesh. So if I look at the
wireframe, you'll notice that all the water
tessellation kind of stops like-- hang on. Yeah, see out there,
on the horizon, where all the tessellation stops? That purple, by the way,
is the post-process mesh that I was mentioning before. So that's that. So that's the tile
size of the far mesh. So if I delete that,
now there's no far mesh. So you'll just have nothing. So what I do instead-- and there's no reason
to set that small. You can set that up to
infinity if you want. Well, maybe not infinity,
but something bigger than you could have to worry. And the reason this is
looking different right here is because there's
no landscape underneath it anymore to draw,
so the depth is different. But if you go in here-- So this is basically still
a child of the same parent. The main difference is it
just has everything unchecked. It doesn't even have waves. So like that's pretty much like
the bare-bones, single-layer water shading. I think it probably still
has the fluid sim on. That's why the
instruction count is up. I need to put this
behind a switch as well. Ideally,
everything is behind a switch, and the far mesh is really cheap. But yeah,
you can put an opaque shader. You can do whatever you want. It doesn't have to be water. It doesn't care. Oh yeah,
so what I just did here is I changed the material
for the ocean. And I changed it to use
a caustics material. So you can see,
next to the non-caustics area, it's not matching. But I'll show what that looks
like in the material here. Oh, I just already had it open. OK, so all of the caustics input-- here is the single-layer
water material. There is a Caustics
input node on there. And then here is the
Caustics function. And this one is actually
using a volume texture. And by that I mean it's
an actual 3D texture, not like a pseudovolume. We can look at that here. So this is the volume texture. And here's a new mode
where you can actually look at volume textures as a volume. So I would say this is like a
thin, shallow volume. So it's actually like-- the number of frames is going
in-between the z component. So it actually is only-- I think it's like 64 frames. So it has much more
horizontal resolution than it does time resolution. But you get seamless blending
on all three axes with this. So that's neat. And it also adds in the
simulation caustics. So I'll show-- it's a
pretty simple material. It's basically just a
volume texture lookup. There is a little bit of math here to kind of take the light vector
and parallax the caustics so that, when you rotate the
light, it kind of projects it up to the water plane,
so based on water depth. And you see we get
water depth by getting-- there is this
WorldPositionBehindWater which is using the scene depth without water-- scene node, scene depth? [CHUCKLES] Something
is wrong with me today. There you go-- scene
depth without water. So this is actually how,
inside the water shading code, it gets the distance from
water to behind water. It gets like scene depth
without water minus scene depth. So this is kind of doing
that same sort of thing here. But then it uses that depth
to figure out the world position behind the water. Then it can figure out the
depth by getting the difference in the z values of
those two vectors. And then it can use that
to basically parallax that caustic. And then all it's really doing is there is an append somewhere. Where is it? Oh yeah, that's this image. Here we go. The append is just
appending time as the z. So for 3D texture, you don't
need like a flipbook function. You just look up it
with two 2D coordinates, and then you set your
z-coordinate to be time. And then you just get a flipbook
for much cheaper than doing it with 2D textures. And then, over
here, this is adding in the simulation caustics. So it takes the normal
from the simulation, and it uses that to perturb
the UV of the caustics normal,
or the precomputed caustics. And then it takes kind of a
finite difference and extracts kind of a focal band
from the blue channel. And that's just kind
of a cheat to get some caustics-like response
out of the simulation. And I'll see if I can kind of
point that out in a little bit. But I guess we can show
the caustics map itself. So this is just showing
it applied in the world. But you can also apply
it, rather than doing it as a caustics input, it can be done as
a light function. It's just there are
different trade-offs and different complexities. The trade-off with this
method is I actually increase the refracted
scene depth quality. So by default, in the engine, you get a little bit
lower-quality scene depth. Because actually what it does
is it half-res samples it. So you lose some resolution. And the reason it does that
is because single-layer water renders as a compositing pass. So we first render
the regular base pass. Then we render water. Then it composites them together. And in the past,
where we're compositing, it downsamples the
existing scene color and depth to make some of
the refraction in a scene color look-ups more affordable. So you can tell we lose
a little bit of quality because we effectively lose
resolution in the position that we reconstruct. So we set it back to 1. And then you get nicer results. But going to the
caustics example map-- we've got our first crash. >>Victor: There we go. >>Ryan: Want to go
through some more questions while that reloads? >>Victor: Yeah,
that sounds good. Can the water system
be used to create more indoor-centric water
bodies without terrains, such as aquariums,
ponds, et cetera? >>Ryan: Absolutely. I forgot to mention that one
when we looked at the types in the beginning. But in addition to Ocean, Lake,
and River, there is Custom. And with Custom,
you specify a static mesh. And you also can opt out of
the terrain carving features. So that's what we
do in Fortnite for-- for example, there is that
nuclear reactor with the core. The cores are actually
regular water bodies. They just have a custom mesh
just set to a flat plane. >>Victor: That's awesome. I'm very excited to hear that. There are some general
questions about a sample project or any way to get to
break down everything that you've been working on here. >>Ryan: Yes,
so the current plan is we're going to try to
include this water sample project that I'm in right
now, which would include that little beach map, as well as like the
little fluid sim example. So yeah, it's probably not
going to have a ton in it. It's going to be a beach with
some rocks, maybe a little-- I'm in. Has anyone else ever gotten this
bug, where you can't actually click anything? I'm going to have to
restart the editor again. This happens to me sometimes,
when I'm screensharing, when I start the editor. The only way to close is that. Sorry again. >>Victor: That's all right. We still have a little bit of
time as long as you're good. >>Ryan: Yeah, no,
what are some more questions? Hit me with them. >>Victor: Yeah,
so during the scene, when you were showing off the buoyancy, and waves sort of bouncing
back from other static meshes or skeletal meshes in the
scene, there was a hard shadow on top of
the water as well as one below. And they were wondering
if it's possible to remove that top-- the hard shadow that
didn't look very realistic. >>Ryan: So here,
let's put on our rendering hat. [BOTH CHUCKLE] I'll show you what you need to do. So yeah, that's actually
something Sebastian wrote. And he started working on a
prototype of a volume shadow method for it. But it is not on by default. So I have my own little
experiments in here too, like this chromatic spread. This is the
SingleLayerWaterShading.ush. So this is, for example, where the caustics
lives right now. Like I added in this
little caustics line to hook up the caustics. But you see there is this
#define VOLUMETRICSHADOW 0. If you set that to 1, what it does is it will actually evaluate
this code block in here. And what this does
is it raymarches the shadow map instead of just
looking it up at the surface. So then you actually
do get that connection from the bottom and top shadow. Although it's probably still
not going to be enabled in 4.26. You'll probably still
have to edit code. And there's also another
problem, when you enable it, it'll fail to
compile because there was some engine
change in this line about the compute dynamic shadow. It will not find
it because you have to move one of the includes
in base pass pixel shader for forward lighting
common to exist before single-layer shading. Don't ask me why that changed. I just had to figure that out
when I was testing this myself. But yeah,
this is a fun place to look if you want to look around for how
the single-layer shading works. Some of it we went over when
we talked about the absorption coefficients. But if you want to learn
exactly what it's doing, it's all in here. But yeah, like for
example, this is where it's grabbing
the Caustics pin input. And this is how it's
set to make sure that it doesn't go above 0 or below 0. And if it's not connected,
it's just going to be 0 or it's going to be 1. Yeah, so there is plenty of stuff that will probably be happening
in the future with water. All righty,
so last thing we'll show here, this is the caustics generator. And this works very
similar to what we saw before with water
bodies, the main difference being that-- I was on the wrong Blueprint--
the main difference being that it has waves
kind of right on itself. And it's meant to be-- it's an editor-only class. You cannot place the
GenerateCaustics in game. And that's because it's
an editor-capable class. But what it's designed to
do is generate a texture that you want to render out. So by default, you set up things
like the water depth defines the caustics or defines
how deep you want to render. You can say how much
chromatic aberration you want. You can say what is the
world size of the texture. And it will kind of adjust the
preview scene to all match. And then you get your own
wave generator as well. So you can change the-- I think I'm not set to
generate waves right now. Yep. You have to check
the Generate box. Otherwise, it'll just use whatever waves exist in the scene. >>Victor: Got it. >>Ryan: Forgot. Where did I put that Generate? It's right there. OK, so yeah,
it lets you really-- you can get some pretty
specific caustics with this. You can change the
resolution of the actual mesh so you can get
sharper and blurrier. Generally you don't need to
go too high because you're going to probably downsample
it when you export it in the end anyways. So the general gist of this
is you tweak your waves and you tweak your caustics to
the desired depth and result. And then, from there,
output and animation is going to determine what
you're going to do with it. I'm going to tweak
this a little bit more because I'm not happy with
that, Uh, Waves. Let's see, so yeah, we need a little bit more variety. There we go. So we've got that. If you just press Begin
Rendering when you're on Render Single Frame
Only, that's just kind of leave this
in a dynamic preview mode where it's just always
capturing the current frame. But if you stop that and set it
to Render Animation Using Time, then what it's going to do is
just use all of these settings here for making the final Sub UV. So we could say,
let's do 8 by 8 frames. And frames per second is
really just how much time passes between frames. So now, when we press
Begin Rendering, see, we saw it kind of fill out
those frames one at a time. And you might think, oh,
why did it start in the middle? That's because it has to
make this a looping effect. So it kind of has to do
the whole encode time and loop on itself. So it actually does render
from the middle that way. And now what we're
looking at in the end is the actual Sub UV result.
So obviously the more time you have,
the choppier it's going to be. So if I set like a low frame
rate, like 5 frames per second, this is just going to jump
around like crazy, right? But let's capture at 60. Now it's going to
be really smooth, but it's not going
to move very far. So in this case, that's actually
pretty good for this value. But let's say we
captured it like 150 FPS. That's actually probably
going to not work out. So you see what ends up happening? Your caustics don't
really move enough. It just like lerps back to
itself if that makes sense. Especially if-- I'll go
with even less frames. Yeah,
so here's what happens when you try too high of a frame rate. It's like it was
trying, it's trying, it's trying, nope, nope. And it falls back down the hill. So you kind of want to
pick out the right frame rate for your caustics. And then there's this
file path thing here. Once it's done, all you have
to do is press Save Texture. And then it's created for you. So if you go to Water, Caustics,
it automatically added that 2 at the end, because. So there it is. And there's a couple other things to keep in mind with this too. We go back down to Preview
Scene, for example. Right now where we're looking
at the Light Function Caustics mode. So what that means is,
if we actually look at our light, we actually have the Light
function right on the light. So it's got the render
target applied there. But there's kind of a
complexity with that because light functions
can only be clamped-- the texture cannot go
over 1 in the material. So that means we
actually have to boost the value of the light. So the caustics has
to be normalized by the max texel brightness. So that's why it looks
like a darker texture. So the boost factor gets
stored automatically for you. It's this 32. So that means,
with the caustics texture, the brightest texel was 32
times brighter than the rest, or 32 times brighter than neutral. So what you actually have to do-- notice the light is
really bright now. We boost the light by the
caustics normalization factor. And then we set the
Disabled Brightness also to be the normalization factor. So basically it's saying we
make the light way brighter, but then we agree to set it
back down to the original value. So that's all you
have to do there. But you can also just change
the preview mode right on here if you want. So I'm going to
uncheck Light Function. So now we're looking
at regular caustics. And in certain angles,
this is the half-res buffer that I was talking about. You see those lines? >>Victor: Yeah. They're coming through. >>Ryan: So they go away
when you set the full resolution. So this is not
light-function caustics. This is in the water body. And they're very similar. They look slightly different
right now because of a very slight difference in how
the refraction is computed and also because the-- so the water material
one can be RGB. So you see we have
this chromatic spread. We can set that to 0, 1, 2,
we can set it really high. But light functions
are only grayscale. So that's another difference is
the grayscale light function. But it's basically the
same technique for both. And I think it's really not clear yet which technique
is going to win out, because it depends-- with light functions,
you end up paying more cost for the whole scene. Because you look up
that caustic texture even if you don't render
it above the water. Because you're just masking
it, you're not actually dynamically branching it. And you also have to pass in
things like that global terrain water texture to be able to
know the water height everywhere in the light function. And that might be not
ideal for certain cases. So the material-based
caustics is better because it restricts the
cost just to the material. But then there's
different downsides. For example, notice,
right now, we're looking at the light
function caustics. And because it's light function,
it's automatically shadowed. But the non-light-function
caustics, it's not shadowed. We still have caustics
in the ambient-- I mean, it's not a deal breaker. I don't think most
people will care. It's just one of the things. It's like, yeah,
the light function just gets shadowed
automatically because that's what light functions are. And I would say, for something like an
aquarium, where you have an object in a room,
the light function caustics are probably not
going to work either. Because you'd have
to do like a raycast to determine if you
hit the aquarium, and if the ray went
through all the way, and all that stuff. Whereas you could just
put the caustic shader directly on the water material,
and then it would work. It's just you have to contend
with the downsampling precision problem. And then the final
option is there's this analytical caustics. Ooh, it's getting way too bright. I'm not sure what's
going on there. >>Victor: Discord? >>Ryan: Hang on. Let me resave that. I'm not sure why
that's so crazy bright. Hmm. Well, we can take a look at that. So the way all of these
caustics things are organized is under the Caustics folder. And then under
Materials > Preview, there is an additional
copy of water materials that have the preview
functions all. This is pretty simple
water material. It has basic water
Gerstner waves and texture for the material itself. And for the scattering
and absorption it's the same as before. The only difference
is this one has the three different types of
caustics gated behind switches. So that's why there's
the different instances. And the Blueprint is basically
automatically picking the correct one based off of what you choose down here for
Light Function or Analytical. So the one we're
looking at here would be GerstnerWaves_PreviewOnly. So this would be-- this caustics brightness thing
shouldn't be that bright. But we can adjust the
caustics by looking at this WaterCausticsPreview_Analytical. This basically is coming
up with these caustics using finite difference methods. And it's bugging me that
it's so crazy bright. But let's see. You can still kind of see it. Let me-- oops. That must be being controlled
in the Blueprint here. Just going to quickly put
a mask on this since I don't have time to fully debug it. This shouldn't take
too long to build. Any other questions to rattle
off, Victor? >>Victor: Yeah,
someone's curious if it's possible to create
circulating ocean currents. >>Ryan: So I would say
that you could do that using just flow maps and things like that. But currently it's not
going to communicate to the rest of the
gameplay system. So like the gameplay
character swimming is not going to know about those. So I would say that's more
an area of future research. But you know,
we do have some people on our team now who have experience with that. I think what happened
is the normalization factor from the other caustics
was bleeding into this one. But you can see here,
these are the analytical caustics. So they look different in that
the features are not exactly the same. But they do follow the same
pattern of the actual waves. Let's see we go ahead and
disable the freeze time. Oh, do it on the caustics. So the analytical ones
are nice because they work with the pattern without
having to make a texture. They just kind of just work. But they're a little sharper. And they take some fiddling. But any waves that I do set,
it is going to be reflected. And the way that you kind of get
that to work is there's this-- it's basically like
a finite offset. And the size of
that offset kind of determines the size
of the caustics band you're going to be extracting. And there's also some
depth-based spread stuff. But it's a little tricky. >>Victor: There
was another question. How does one use
Simulation Stages? Can't seem to find
any information on it. >>Ryan: There we go. So this is showing that you
at least get the same pattern. Yes, so Simulation
Stages, I wasn't planning on really going
into very much on that yet because, well, for one, Wyeth Johnson and
Jon Lindquist are doing a stream, I think,
in maybe two weeks or something. >>Victor: It will be
in beginning of November. >>Ryan: Oh, OK,
so it's in like a month. >>Victor: Yeah. >>Ryan: But I think those
guys are planning on talking more about those sort of things. And right now, Shader Stages is
in a state of very wide flux. So anything we say could send
people down a wrong path. But I mean, since we're already in
here, I can just mention, just really quickly,
the basic idea, as long as people
promise not to get a-- just know you won't be able
to copy this right now. Like what's Shader Stages in 4.25 right now is completely different. >>Victor: We'll ask
for some promises in chat. >>Ryan: I'm
looking for the effect. Hang on. Here we go. So the basic gist of it
is that you have grids. So there's this emitter grid. Where is it? It should be showing. There it is. So you add grids through your
emitter, Grid2D Collection or whatever. And you set them up in
your particle spawn, setting it to be 256. And then when you have
like a stage later-- so this is rasterizing
a particle to a plane. Basically you set the stage
to point to that grid. So like this Grid2DInput
is EMITTER ParticleGrid. And then inside here,
this is a particle stage. So it's basically using
particles as the thing. And then, in here, it's basically doing some masking to be like,
OK, this part builds a sphere to make it round. This actually renders a
radius inside of the grid. So each particle is just
writing one texel at a time. And you tell it how
many texels to write. And it adjusts that
texel based off of how in and out of the grid that it is. So when you're looking at
it, that's how the points are shrinking. It's basically saying, the radius goes to zero as we get radius
away from the plane, which is all this math. So this is a super,
super bare-bones Shader Stages. Usually people are using them
for iteration non-positions and other stuff. But here I am just using it
to raster out a position. Or not a position, just a value,
just to feed it somewhere else. But yeah, hopefully,
come October, you guys will get a much better look. So yeah, I'm hesitant to
say any more than that, just because, for one,
it's changing a lot. For two, it's more the Physics
team's feature to show off. So yeah, anything next? >>Victor: Yeah,
we got a few more. Is the caustics sample
project and system similar to the previous
work on caustics? Ryan previously went in depth in
other videos on how they work. >>Ryan: I mean,
it's similar behind the scenes. I mean, if we can kind of
deconstruct it really quickly by, in here, if you turn off
this Show Water Scene, now what we're going to see, we're actually
looking at particle-- they're static meshes,
but I call them particles just for simplicity. So yeah, it's rendering
out these particles. And there's a material for it. You can load the material. Let's see. Of course that's not helping me. Caustics > Materials > Generation. So it's this Mesh Scatter. Now, brace yourselves. This is a fairly
complicated shader. Because this shader is
doing a whole bunch of stuff to generate tiling Gerstner waves. And there's this whole
pre-integrated spectrum thing. But the part that I
really wanted to look at was there's this Photon Scale
that, if I adjust it back down, you'll really be able to see
the individual particles. So first let me
reduce the resolution. How can I select this? OK, so resolution is 1,024. Let's go down to 512. And then so what it
normally tries to do is it makes these particles
scale with the resolution. So the higher res, you can see
it's scaled them down for me. But in the shader,
there's an additional expansion. And what these are doing-- there's a bunch of other stuff
in here to make this thing tile and wrap. So if we disable the wrapping-- so that's without wrapping. You see that we don't have
seamless tiling anymore. So if we were to-- it's hard to tell here,
but it would break the tiling by disabling that. And then we control
the chromatic spread. So the chromatic spread, this part is actually probably the only
interesting technical part about this whole thing. The rest is all pretty standard. But basically what we do is we
take these individual photons, and we kind of stretch them. Let me make the
particle even smaller. >>Victor: And you actually
refer to them as photons. >>Ryan: Yeah, I call them
as photons because they really contain a full spectrum each. And so, as it gets
longer, it basically spreads the rainbow spectrum
more to its component parts. But it's doing that kind of
without any additional blurring or additional lookups. And the way that
works is kind of neat. I'll show that. And I mentioned this briefly
a while ago on Twitter. But there's this pre-integrated
spectrum texture, which this basically
represents a single photon. At the very bottom
down here is where a photon without any spread. And it's encoded
where the spectrum is set to equal where it's
indexed as the photon spread is 1/photon radius. So basically we tend toward black. And so this is energy conserving. So as you get to a
point, you notice there's this kind of like
antumbra in the falloff here, where it's just this
white-and-orange region. So this is where you would
have chromatic spread, where the aberration was
about half of the photon size. You start to see the color
fringing first before you see the full color separation. So it gives you that accurate
energy conserving response, which is interesting. So that's basically just how it's able to do that efficiently. The more standard
way of doing this is just to do three different
caustics renders, one for red, one for green, and one for blue. But the reason that
didn't work well for me is because I was also trying
to use this for other purposes. So you can also take advantage
of this rainbow gradient. Instead of using it as
chromatic aberration, you can also kind of exaggerate
the chromatic aberration and then blend between the
different aberrations based on depth. And you can kind of
use it as a proxy for storing depth variation. So almost like a
four-dimensional texture, where z is time, but color is now z. And what that looks like-- let me see. There's actually a mode in here,
it's just not quite working by default at the moment. So for render, you can render
animation using time or you can render
animation using depth. And with render animation using
depth, what it actually does instead is it uses the-- instead of just
animating the time, it will animate the depth as well. So like if I set 2048 and 0,
let's make a flipbook of that. That did not work. OK, well that broke. So what that was supposed to do-- oh, never mind. I selected the wrong choice. There we go. >>Victor: Whoa. >>Ryan: So here. So now what we're looking at here is we're looking at increasing
depth over time instead. So you could render
a single time frame, and then choose
between that instead of animating the position. But the other option there,
you go back to animation using time. And you set that back to 0. But you exaggerate the chromatic
spread something crazy. Maybe too crazy. That doesn't look right. Here you go. So yeah,
it's hard to look at by itself. But when we look at this
afterword, what we're looking at is basically each of these channels
will have increasing chromatic aberration,
which is also an interesting proxy for depth. But because we did it in that
smooth way with that spectrum, it's not like we just have
separate, discrete points. It's more like they're
continually connected. So like when you zoom in,
it's a continuous shift between those colors. So you can actually then
extract that after the fact and use it to animate the
depth just by color picking. There's no working example
of that right the moment, but it's pretty powerful. I posted about it on
Twitter in the past. Yeah, any other questions, Victor? >>Victor: Yeah, a few more. So I know you mentioned
it earlier in the stream, but for everyone that
joined a little bit later, when can people get
their hands on the tools? >>Ryan: So this will
be first available when the 4.26 preview comes out. >>Victor: Which is
today, the first one. But it's not in the first preview. >>Ryan: Oh,
sorry, preview 2. My bad. I didn't realize we
already had that. Yeah, no, we did not make it in
time for the first integration. >>Victor: So
keep your eyes out. I have a few more. But we're at 2 and
1/2 hours right now. Let's do a last question. Do you have any tips for
troubleshooting issues like the gap between
the lake and the river? It was in the beginning
of the stream. >>Ryan: Yeah, in that
case, I think what we're really going to have to
do is include a set of guidelines that make it obvious what those limitations are. Like that same thing
could happen here. And in fact,
I'm curious that it's not. It's hard to say. What I would suggest is
looking at tile bounds. That is probably your
really number-one thing that's going to help
you debugging stuff. Because often,
if the problem exists on the boundary
between two colors, then that's when it's like
something about how you're masking the behavior between the
two different materials is off. But generally it's the velocity
just needs to be zeroed out. Like in this case, it's kind of working
the velocity is full at the end. Because we don't have a
different color transition at the end of this tile. If you see that,
it's still yellow. But if we happen to have a green
there, that might be bad. So having velocity 0 at the
end of your river is more safe. I'm not sure if that's something
we'll be able to do by default. Because when you place a river,
I think it has like 2 points. Or maybe it has 3. Let's just try it. Yeah, it's got three. So maybe what we can do is
just, by default, make sure that the
endpoints have 0 velocity. But I think it's a trade-off. I don't know don't know that there is a correct answer there. Foliage goes crazy with the wind. So anything else coming up? >>Victor: The last one was
just a question in regards to, you did a mention earlier
about custom shading models as a plugin. >>Ryan: No, I was mentioning
that we do not support that. And that's why
water was released-- the shading model was released
earlier than everything else, because we did not
have that option. >>Victor: Cool. I think, with that, it is time for both
you and me to take a little break. Ryan, thank you so much
for coming on the stream and showing off the tools today. Make sure you go
follow Ryan on Twitter. It's @ShaderBits. He posts plenty of his work. And it's always amazing to
see what he's working on-- some updates, sometimes
tips, little mini tutorials almost even. And so make sure you follow there. Go through a couple
of things real quick since we're at the end
of the stream here. Make sure you follow us on
social media for all news and updates regarding
Unreal Engine. We post when we're
streaming as well as links to all of our blogs, other cool
project spotlights, et cetera. So that's where you get
the latest and greatest. Make sure you visit
our online communities. If you're new to Unreal
Engine or you're been here for a long time, you're probably
part of the forum on Discord. But if you don't know,
UnrealSlackers.org is one of our unofficial
community Discords. There's plenty of people in there helping out,
participating in chat, doing good discussions about new
tech, old tech, everything in between,
how to use the engine, how to hack the engine,
how to break it. Our forums is also
a really good place. If you want to let us know
what you're working on, you might be featured in
our community spotlight at the beginning of the stream. Make sure you post on either the
forums, the Discord channel, or server, that's also a good
place to do that. Next week we are actually
on vacation-- yay-- so there won't be a stream. But the week after, we'll be back with a group of students who
have developed amazing projects as part of their graduation. And they're coming on to
talk a little bit about what it's like being a student
using Unreal Engine and learning how to
create video games. And then we get to see
some really cool things of what they made. Once again, thanks to Ryan Brucks for coming on the stream. Anything you want to end with? >>Ryan: Thank you guys for
tuning in on the water stuff. I don't know if I still
have the screenshare. I forgot to show that
you can do the material layers on landscape with
the water bodies as well. All you do is you add to
this Layer Weightmap Setting. For example, here,
we're using it to make wetness where the river is. And we're using it to add in
kind of a simplified sand. So we would reduce all
those bumps and stuff. And you get like full
texture support for all this. And you can offset it
and do crazy stuff. So yeah,
hopefully it's self-explanatory. But people might
want a way to do that for having wetness with
their water bodies and stuff. Not that there's not other
ways to achieve that. That's just one cool way,
just check a box, done. But yeah, thank you guys so
much for tuning in today. I had a lot of fun
talking about water. And look forward to getting
it into people's hands. >>Victor: Sounds good. Y'all stay safe out there. And we'll see you
again in two weeks. Bye, everyone. >>Ryan: See ya.