DARYL OBERT: Hey, everybody. My name's Daryl Obert. Welcome back to our
next Unreal webinar. Today's topic is
creating visual effects. We're going to be
looking at a shot that was done for the Unreal
For All Creators cinematic, which is an amazing animation. I'm sure you guys
have all seen it, which is probably why you're here. I've got the pleasure
of introducing you to Malachi, who is one of the
super talented VFX artists that worked on it. So what's going on Malachi? MALACHI DUNCAN: Hi. So my name is Malachi Duncan,
and I'm one of the tech artists that form the really big
talented team that worked on the Creators For All video. Today I'll be showing
you a high-level overview of the transforming
building effects that I did for the
architecture sequence, and I feel really happy to be
able to package it up and share it with the community
because that's how I learned before I got a job at Epic. So I really hope you enjoy it DARYL OBERT: Awesome. Well, that sounds great. Let's jump in there
and check it out. Cheers, everybody. MALACHI DUNCAN: Hello,
and welcome to the creating visual effects for
Unreal Engine webinar. I'm your host, Malachi
Duncan, and I'm a technical artist
at Epic Games, and I recently worked on
the Creators For All video. Here, my main task
is designing the way the buildings of the city would
transform and materialize. And today, I will
be showing you how to make dynamic looking
rigid body effects using Unreal Engine's
powerful Pivot Painter tool written by Jon Lindquist. By the end of
this webinar you'll be able to create
an effect just like this that updates live
in the viewport. The topics that
we'll cover today are preparing production
assets for the Pivot Painter, and the best practices for
asset import, an overview of a simple vertex
shader, and then we'll look at how to complicate
that a little bit more with a ripple effect. And finally, we'll
have an overview of using a Blueprint asset to
create an artist friendly asset for set dressing. Now let's get started. OK, so as you can
see, we're in 3ds Max, and I've taken a
building, and I split it into a bunch of sub meshes. And I have set their
pivots in a logical place for the rotation to happen
when once we're inside of Unreal. The Pivot Painter
comes in two parts, it comes in a 3ds
Max script, and it comes in a material function
library, inside of Unreal. So at least for
the export process, you're going to need
to be using 3ds Max. But if you're
anything like me, you may have started this process
in another software package like Maya or Blender. If that is the case, then
what you have to do is make sure that before
coming into 3ds Max that you have taken
everything out of its groups, deleted its history,
and froze its transforms, and then exported and
imported it into 3ds Max. And that way you should
find that if you have set pivots somewhere else,
then your pivots still translate over to 3ds Max. And then finally, just for
a very last sanity check, is that you should
select everything and then just right click
and convert to editable poly. And that is just going to
make sure that everything is collapsed down. If there's any
deformers on there, or if it's not an editable
poly, then our script will error out once it hits
that particular sub mesh. So this is just making
sure, and it's an early flag if there are any problems that
may hinder you going forward. So where can we find
the Pivot Painter tool? Now your Pivot Painter tool
you can find in your Unreal Engine version. So for me, I have a folder
for Unreal Engine versions. In 4.25, Engine, Extras,
3ds Max scripts, and then you'll find your Pivot
Painter and Pivot Painter 2. We'll be using Pivot
Painter number 2. So let's run the script. We're going to go to scripting. Run script, and
select Pivot Painter 2, and open that guy up. OK, so you're going to see
now we've got a bunch of menus. So we've got our prep tool,
we've got our render options, we've got vertex alpha painter,
and we've got our package tool. Now for this, we're only
going to need our render tools because we've already
done a lot of our prep work already. So we've already
split into sub meshes, and we've already
set our pivots, and we should already
have set our rotation vectors, which we'll go over shortly. So our prep tools
aren't really needed and neither are the vertex
alpha or our package model. These are more for foliage
pipeline work rather than rigid body animation pipelines. So what we're going
to be doing is the script is going to be taking
our selection order, so we're going to create a
selection inside of 3ds Max. In the order that
we selected, we're going to create a new UV
on a different UV channel. So it's going to be
Texture Coordinate, anywhere between two and eight
depending on your art pipeline, but we're going to
keep it at number two. In that new UV
coordinate, we're going to be printing out our
pivot location as a texture. In the alpha, we're going
to do our selection order. This is so that we can do
some debugging inside of Unreal if need be. We know what order
everything was selected in. Then we're going to
select our rotation vector, so that is the vector that
we're going to be rotating around inside of Unreal. So for this, we're going to
be selecting our X vector, and for alpha, we're going
to be doing a random number between 0 and 1. This is going to help us do
some randomizations inside of our shader. So just so it's clear,
our rotation vectors are going to be rotating
around the X over here. And we are making sure that
we are doing this in local space because our script is looking
at local space pivots only. So you might find
that you are in view, but you need to
make sure that you set your pivots in local space. Now, because our script is
selection order dependent, which means that all
of our textures and UVs are being created in the order
that our meshes are selected, it means that on your
first time setting this up, you will need to do a new mesh
export because your mesh has changed. But to do a fast
iterative process, you might decide that
you want to change some of these rotation angles
depending on how they're rotating inside of Unreal. You don't want to have to do
a new export every single time, like a new mesh
export every single time, so what I like to do is
I make a selection set. So we're going
to select all of this here and then
create selection set, we're going to click in here,
and click entire mesh, right there. Now what this
does, is it creates a selection set so
that when we select it, it's selecting our mesh
in the exact same way that we selected it when
we created our selections. And that means that
in our iterative work, we are just exporting
textures, and we don't have to go through
the mesh export process over and over again. So let's talk about the
total number of sub meshes. I personally have
found that using sub meshes around the
2,000 mark, is the most stable. So because of this, I've
created further selection sets for the inside of the building. So if I come here, and have
inner, that's 512 meshes, and that's all the
floors and the struts. And then I have a
different one for the exterior, which is all the facades. It's coming in just
underneath 2,000 at 1,700. And what we'll do is export
these as separate meshes, but we'll play
them back in unison together inside of a
Blueprint, so that they'll still feel like they're one cohesive
mesh, this is just a work around. So following on from that, let's
process our mesh hierarchy. So we're going to come
here now, and we're going to bake the
textures out for that. We're going to just
go to our desktop, and just save them there. And then we'll just come here,
and do our first mesh export. Export selected,
export, export selected. I'm going to do
our building outer. I've already done
one of these before. And we're going to make sure
we have our smoothing groups on, our tangents and binormals. And I'm going to triangulate
on export because I found, especially for this pipeline,
that when we do our combined mesh on our import into UE4,
if we let UE4's importer handle the triangulation, it
never really behaves the way it's supposed to. So I like to
triangulate on export. So that's what we're doing here. OK, well, let's jump
over to Unreal Engine, and we'll look at the best
practices for importing our assets, and our
best practices for creating our first simple vertex shader. I'll see you over there. OK, so now we're
going to go over some of the import best practices. So first off, let's look
at importing our mesh. So we're going to
bring our mesh in. And if you're doing
this for the first time, it should come in like
this, and the only thing that we need to change
is by coming in here, this is normally ticked
off by a default. Make sure that we are combining meshes
because you should be exporting out 2,000 meshes
that are singular, and now we just want to
combine those so that they're all one. You're going to do
an import for that. And then the next thing
that we're going to do, is we're going to
bring in our textures. So we've got our pivot textures,
and we've got our X vector. Your pivot textures are EXRs,
and your X vectors are targets. And the only thing we're
going to change about these, is we're going to open
them up in the texture viewer. We're going to come
down to their texture group and for the EXR
pivot position, we're going to change
that to 16-bit data. And for our X vector,
we're going to open that up, and we're going to change
this texture group to 8-bit data. That's also going to change its
compression setting to a vector displacement map. And now, our meshes,
and our textures are ready to be used
in our vertex shader. So we're going to go to
that and have a look at that. OK, so we are in
Unreal now, and we're ready to start looking at
our simple vertex shader. We are going to get
more complicated with this, but I do want to show you
just the bare bones of the logic, and I think that's easiest to do
on some simple geometry rather than a big massive building. So what we have
here is that we just have two skyscraper-esque blocks. And what I want to show here
is that what we're actually doing is that we are
rotating and scaling our meshes in the shader. And that is the bare
bones of the effect. So although, it can look
a little bit complicated, as long as we boil this
stuff down to what it really is, it makes it a lot more easier
to understand conceptually. So let's just open up
the shader and have a look at what's happening. So first off, what we've got
is we have our pivot position and selection order,
which we're not actually utilizing right now. If you remember
correctly, we put our UV coordinates in
a separate UV channel, and we still need to
find those, so we're creating a texture coordinate,
and in our coordinate index, we are setting that
to 1 because Unreal starts at 0 and not at 1. Texture coordinate of 1 will
match up with 3ds Max's texture coordinate 2. Then what we're doing
here is that we can actually exaggerate certain
axes to make one of them grow faster than the other. So how this works is that
the lower the multiplier then the faster the axis will
grow in relation to the others. So it's just if you want
to make for example, have the vertical
position grow twice as fast as the horizontal positions,
that's what this is for. Then when we use
decode position, which is from the Pivot Painter
material function library, you just type in decode
position, and it's right there. And we want to create a gradient
between our pivot positions, and a point in space. So we're giving it
a free vector here, and we're going
to be transforming this from a local space
to absolute world space, and we'll be finding the
distance between the two. And then from there, we're
going to be subtracting out our heights, and
this height it's going to be the one variable
that drives the whole effect. Later on, we're going
to be having our ripples and our Pivot Painter all
driven from the same value. So this is going to become
a very important value, but this is going to
be driving our effect. Now we have our animation scale. Now our animation scale
defines how big the animation is. It's a divider that defines
how much of this height is needed to move
through the animation. So the higher the
number is, then the larger this
height value needs to be to drive the animation. It's very difficult to
explain that conceptually, but I'll be able to
show you in a second when we visualize
exactly what this is doing. And then we have our power. And this is basically just
going to be an animation ease, and again this will
be easier to show you once we start visualizing the
mask of what we're doing here. So if I just pull this out and
set this to our base color, so in the level, now when
we're previewing our mask, now the 1 values,
so where the Y is, it's going to be our
completely rotated meshes. So they still have
all the potential to come out and be rotated
back into their proper position, and they're also at
their smallest scale. So at 1, they are
scaled all the way down, and they are invisible to us. And at 1, is when
they have completely rotated into their
proper rotations, and they are at
their biggest value because there is
no scaling being done to them because
they're being multiplied by 0. And our intermediate areas
here, so what we call our gradients, this is going to be where
our animation is taking place. So each point
in this gradient is representing a different
part of the animation. So for example, now if I
was to change this to 1,000, you see that we're losing some
of the detail in that gradient, and if I bring that all
the way down to 1, then there is no detail. So our animation would
just be popping from one state to the next. It'd just be popping
from off to on, or on to off. So if I bring this
back up to 2,000 now, and if I change our
animation easing, it's now saying that we actually
get to dark quicker than when we're 1. So it's controlling the easing
in and out of dark and black. So those are those
two conceptual things shown right here. So now we're back in the
material, let's have a look and see what that mask
we just looked at is driving. One thing that I
didn't mention is that we need to add a
saturate, and that saturate is going to be clamping
the value between 0 to 1 because we're dealing
with a massive height value, and massive divide value. So we need to make sure that
we are keeping these values between 0 and 1. So what we're going
to do is that we've got our decode pivot position
that hasn't been multiplied, and we're going to subtract
the world position from that. And what we're doing here
is that we are subtracting the mesh by itself, and
so that should scale it all the way down. So what we're to do is
we're going to multiply that by our mask, and it's kind of
inversing it now because I've been working with an offset. When this is at 0,
when the mask is at 0, we're actually not
doing any scaling at all. So it's going to be
all the way scaled up, and when this mask
is at 1 in the white area, then it's actually scaling
it all the way down. So that's what's going on here. That's how we're
going to get our scaling. And then from that, we're
going to do a rotate about axis. And we're going to find
what axis to rotate around by getting our rotation
vector from our vector texture. We're going to do a
decode axis vector, the same as our decode
position, but just for vectors. And that's going to go in here. And then what
we're going to do is we're going to get
our rotation angle, and from that we're going
to grab our random 0 to 1 from our alpha channel
of our vertex texture. I'm doing a clamp
here of 0.1 and 1 that's just because I just want
to minimize having 0 values. I want everything to
have a slight offset, so that's what I'm doing here. And then I'm multiplying the
mask by that random value and putting that into
the rotation angle. And then, for our
pivot point, we're just grabbing that
pivot point again straight from our texture. And finally for our
position, we now have a scale position
because we're scaling it here. So we're taking
that scale position, and we're adding back
in our position offset. And so we're adding
back in our world position because all of this stuff
here that we're calculating is that we just calculated
our taking the offset, so we actually don't have the
position anymore because we're subtracting from it. So by adding the
world position back in, we're actually
getting our position. So that's what's going on here. And then we add
that into our scale, and that goes straight
into our position offset and that is that done. Now, one of the other
things that we need to do is we now need to
calculate our normals again because we are rotating
and manipulating vertices, so we also need to
update their normals, so that they light
and shade properly. So to do that, we're
just going to get our rotation axis, which is the
same thing that we did up here. It's going to have a
vertex and template to take that from the vertex
shader to the pixel shader. And we'll be doing the same
thing for our rotation angle, we've taken the
same rotation angle that we did for
rotate about axis, but we're just transforming
it from the vertex shader to the pixel shader. And then finally, if we already
had a normal map on this mesh, we had a tileable
tile texture on there. And we want that
to be rotated as well, and those normals to be fixed. Then what we do, we just get
that normal map as an input, and we're going to transform
that vector from tangent space to world space and plug that
straight into the world space vertex normals here. And then, in that
new tangent space, vertex normal output
is going to give us our new updated normals
that account for the rotation and scaling. That is that in
its simplest form. That is our vertex shader that
is manipulating our geometry. OK, so now I can show this
on something a little bit more complicated, but it's
the exact same principles as we saw earlier. So here is my height. I just renamed it as atom
phase inside of this Blueprint. And I have two
Pivot Painter meshes stacked on top of each other. So that's the facade
and the inside meshes, and I can control
them separately with the inner struct
offset, so the inner struct can grow quicker or can grow
behind the exterior meshes. What I did, is I
created a variable as well that I could
control in the viewport that defines where that stop
position is, where that stop point is. And I did that first off,
by creating a function and what that
function is, it's just a set vector parameter value with the
name of the variable that I'm setting which in this
case is going to be pivot stop position. And then, I created a
normal float 3 vector, and I ticked show 3D
Widget and made it public. And then I just put
that into the color value, so that's what's getting sent. And then finally, what I did
is I wrapped everything up into a material function,
I brought the textures to the outside
of the function so that each instance could
have a different set of textures if needed. There's also a normal input
that take external normal map in. And then I could plug that
into any master material that I want to become
a pivot painted building. I could also add
some switches, so that I could switch
them on and off, so that it didn't affect
every material instance, just material instances
that I wanted. And then, inside here
just to add some inputs just as they were used. I mean, that allowed
me to really quickly get exactly what you see here. It just expose them
to random bits and pieces that I thought would be
useful to have top level. But you can see, it
is very much the same as the small scale
building, which we saw. If I can change
the exaggerate, I could make the vertical
movements twice as slow as the
horizontal movement, so that it grows out
quicker than it grows up. Or I could change that
around to make it twice as fast, so that it grows upwards
twice as fast as it grows out. There's a huge amount
of stuff that you can do just with this set up to change
the way this effect looks, but saying all that, let's
take a look at the ripple effect and see how we can add even
more complexity on top of this. OK, so now we're going to
start looking at the ripple effect. And this I just ripped it
out of the main material and turned on a
mask, so that we can see what each layer of
this ripple effect is doing. If I were to play the
final ripple effect, you can see that
what we're getting is we're getting a bunch of
these rings coming out here. And these rings are growing
over the entire building, and eventually there
is another circle mask that comes in and takes
it all off as it gets bigger. So let's bring this
back down again, and we start to break this
apart into its individual elements. So if we tick all
of these off quickly, so the first thing
that we have is we have an outer
ring, which contains the entire ripple effects,
and none of the other ripples will ever extend here. And it will all be contained
inside the biggest ripple. And then after that we have
a slightly smaller ripple that we can also offset as well. So we can say whether we
can bring it closer into the larger ripple if we need to. We've got this medium
ripple offset which we've set, and that comes in just
after the large ripple. These are two ripples
that we can really look develop into how quickly
they come after each other. And finally, we have
these small ripples, here. And these are meant to
be more subtle than the two big ripples. Just imagine that these two
big ripples are coming through, and then this is like the
[INAUDIBLE] of and the smaller effect that these ripples
have on the buildings if we just hide the bigger ripples. But we have these
smaller ripples here that just pulse
out for a little bit, and they're really low strength. We can set them a
bit higher if we needed to like later on down the line. But they're meant to just
be really, really subtle just to have a small little shimmer. So how did we build this effect? So it all starts off
with the ripple center, which we can control still,
so we can still come in here and change our
ripple center, and move the whole effect around. And that's what
this is doing here, so we're getting our
ripple start position and we're transforming it. And then what we do,
we have a master function that is creating those
rings, and it's really simple. So first off, we have
some inputs here that is the ripple
animation and speed. So we are bringing
in that height value that we had for
our pivot position that was driving our
Pivot Painter shader, and that's just
what this is here. So then we have a
multiplier afterwards, and that's giving us our speed. And that's just giving us a
percentage of our animation phase, so we can offset how
fast this animation is acting to the rest of the system
by giving a percentage of the animation phase. So everything's kind of
offset, that's what that speed variable is giving us. Then from that, we're
subtracting our phase offset, and that is just so
that we can offset this effect to our effects
in the medium ripple. This is how we're offsetting
its position from the larger ripple. And then we're
going to break it off into the inner ripple
and the outer ripple. So essentially what
we're doing here is that we're using max nodes,
just to make sure that we're always sending positive values. We're creating a
sphere mask, and we're taking our circle origin, which
is the ripple start position, and we're just comparing
that against the world position to create two sphere masks. However, the ripple inner
has a subtraction that tells us its size, and then
we're just going to subtract these two
together, and that will create a nice little ring for us. I mean, coming
from there we just have some controls to
control this ripple's contrast and to control
its strength, which is what we have going on here. We do have some other outputs,
so we can use them elsewhere. For example, this is
the circle outer mask, so if we ever wanted to find
out where the edge of this ring is then we've got that here. If we also wanted to
get the circle size just at the scalar parameter before
it goes into the sphere mask, then we have that too. And we have the
combined masks before we add all of our multipliers. If we go back here, so then
we just do the same thing twice. But as you can see,
we've got this large ripple offset as well. And that ripple
offset here is just making sure that this
medium ripple stays inside of the large ripple. And this large
ripple offset is offset from the edge of the effect. And then finally,
what we're going to do, we grab our circle results
and then we add them together. And then that we'll cover a
little bit later on because now we're going to
come back up here, and we're going to talk
about the small ripples because they get
added up together. So our small
ripples, again we're referencing the
ripples dot position. So if we call our
variables the same thing, then they just become
instances of each other. So whenever you update one,
it will update every instance of it in the shader graph. We transform that position
again from local to world space, and what we're going
to do here for the ripples is we're actually going to
use the sine wave because we don't want to have to keep-- we're going to get a
really big and bloated graph if every ripple we had
if we had to do these. So what we're going
to do then, we're going to create sine wave. And the reason why
we're creating a sine wave is because the sine wave
is going to go between 1 and minus 1, which means
that whenever we're at 1, then we're going
to get a white value, and whenever we're
at minus 1, we're going to get a dark value. So looking from
the top down, we're already going to be getting
white, dark, white, dark, white, dark. So we're already
getting a ripple. All we need to do is
give it some coordinates, which is what we're doing here. So we're just going to get the
distance to our absolute world position. And we're going to
add a divide on that, and that's going
to be off our scale. Then again, you see we're
referencing the height, which is also what has been
referenced down here, and will be referenced in
our pivot shader as well. We're multiplying that
by minus 1 because we want it to flow in
the reverse direction because without this, then
the effect comes inwards instead of pushing outwards,
so that's what that minus 1 is doing. And then you're giving
it a speed variable. So again, we're just giving
it a percentage of this height, and then that's dictating
the speed of that. And then we're going to
add that to our coordinates that we've got here,
and we're going to put that into a sine wave. And then again, we're
just doing some contrast, and then finally, we're
going to be multiplying it, the same way that we're
multiplying our strip down here that we haven't covered yet. To really get a wave feel, waves
tend to be really concentrated in power at their centers,
and then as they push off, then they lose momentum,
and they lose strength. And that's basically
what this function is doing, it's phase dampen. So what we need is that
we need to have an animation phase, which is what we've
got here, which is our height. So as this increases, we
want the strength value to decrease because that means
that the longer the animation is going on, then
the less powerful the strength should be. So it's just a really
simple function, and what's going on in
here is that we have a value to dampen over the animation. And then what we're
doing is that we're taking a multiplier
because we're normally dealing with large numbers,
we're using our anim phase. So we're just taking that
value, and multiplying it by 1,000, and then we're going to divide
that by the animation phase, and we're going to
have a multiplier on that, so that we're only taking a
percentage of the animation phase. So that gives us
our dampen amount. And so then as this animation
phase increases in value, as the animation gets older,
the value will get bigger. So the value that we are
dividing our strength by will get bigger. Meaning that over time
that value will decrease, and we are using that
on all of our sphere masks. So we're using it here,
and here, and also we're going to be using it here. Now finally, the two
things that we have here, we have these small
ripple exclusions. So now, for example,
what we're doing here is that we're getting the
outer edge of the large ripple, so the furthest
extent of this effect. And we're basically
masking out everything that's outside of that, so that
the small ripples can never extend out past
the largest ripple. And then here is
the falloff effect that's going to wipe over everything. So this is our duration
that we've got here. So we have this
small ripple offset, which we take it from our
circle size of our large ripple. So from there we're
subtracting out a large number, and that's basically how
many units that this whole thing is going to live on for. So right now, we've
got it set to 2,000. We're making sure only
setting it to positive numbers, using the max node, and
this comes out the very end, and if we visualize it
here, we visualize it by spreading this out. What you're seeing here
is this other sphere mask, which comes on at the very
end and starts wiping everything. If I was to change this
value, so just scoot that over. If I was to change
this value now, spawn small ripple
spawn duration, if I change that to 5,000
units, for example, then we're going to get an extra 2,000
units that we can move through before it starts to wipe. So that there is
just making sure that we are defining
the window at which we can spawn our sine wave. Then we add that in
on top of our medium and our large ripple. And then what we do here
is that we're doing a lerp, so this is allowing us
to paint in the viewport, so that we can art direct where
we want these ripples to effect and where not. So if there is any
red vertex colors, and then that value
is true, then we're going to send a
value of nothing, so there won't be any
deformation in those areas. And then what we're
doing over here, is we have our vertex
normal world space, and we're just masking
out the R and the G, and just appending
in 0 for the B. Now what this means
is that we are not going to be doing any
transformations in the Z-axis. That just works for
this effect, I mean, if you're building an
effect similar to this, you may want to have
something in the Z-axis, but we decided for
this effect that we only wanted it to be in
the X and the Y-axis. So we're multiplying anything
that would be in the Z-channel, is multiplied by B.
And then all of that just goes into
our world position. And we've done
some masking here, just so that I could
visualize it in the viewport, but that is the main overview
of what the shader was doing. OK, so finally we're
back in the level, and we're going to turn
our strength back up. And we just want
to visualize why it was important
to start masking out certain areas of the mesh. So you can see here, we've
got this problem area in the side, and this could be part of the
effect, if we wanted it to be. If you wanted the side of
the building to pulse and rotate like this. This wasn't necessarily
something that I wanted. So when we go down
to our mesh paint, and we can visualize
our red channel, we see that there's
no red channel here. So if we wanted to,
we could turn it off now, or we could come in and paint. And if we paint red here,
we can see that actually we're going to be painting away
the effect in this corner. So it would have
had the illusion that the sides of the building
are able to contain the ripple. Turn on our red
view mode, and just make sure that we get a nice
paint here, and turn that off. I mean, now you can see
that the ripple isn't giving us those problem areas
in the corners anymore. So let's go and take a
look at the final effect. So here is the final
effect now, the final effect where we have a
transition area just outside the ripple, where
our Pivot Painter is happening. Our pivot point is also
happening in the middle, in these structs and columns. And the main portion of the
effect that we're seeing there, that's pushing everything
out, is the ripple. So it's like that the ripple is
pushing into our Pivot Painter materials, and our
Pivot Painter materials is trying to keep up with this
oncoming wave that's coming up. So the way that we've combined
these two effects is we've just done another
transition mask, and this transition mask
lives outside of everything. So the large ripple sits
inside of the transition area, and the transition
area comes down here, and if we're using our
ripples, then our Pivot Painter can only happen
inside of this transition area which you've got here. So this is just the sphere
mask with the height and world position going into there
without any subtractions. Whereas over here, now,
we have a larger ripple offset, and this offset is offsetting it
from the edge of our sphere mask. And then, all
we're doing is we're going to take our output from
our vertex normal world space, and we're just going to add
that into our world position down here. And so after we've
done our scale rotation, we just add in our ripples,
and then that is going out to our world position offset. And it's as simple as that
when we are combining the two. One other thing that
I haven't mentioned, when you're ray
tracing, our meshes need to evaluate
the world position. So if you tick this off,
you see that the things that are happening on the shader,
aren't affecting the lighting, so it's still being shadowed
as if this building whole. So you need to make sure
that you select your mesh, and you tick evaluate
world position offset. And then that way, everything
is going to light and shade properly. So I'm going to teach you
quickly how to use a Blueprint asset, so that we can quickly
change a bunch of variables just by drag and drop. So it's really
artist friendly when you hand this tool
off to a set designer or something like that. All right, see you there. OK, so currently,
I'm in the Unreal For All Creators
project, this is a project that will be released to the
Marketplace for free for you guys to delve into the shader. And I'm here to talk to
you about data assets. So first off, let's explain
what a data asset is. Now, for each one
of the buildings, they have multiple shaders,
and they got two pivot buildings in here, so there's
one for the outer and there's one for the inner. So there's a lot of variables
that aren't going to change and don't need to be
used for look dev purposes. They're just variables that
would be set and forgotten about. That's quite a lot for an artist
who doesn't know anything about this set up, to
come in, automatically know what shaders
need to go where, what textures need
to be put where. That's what our
data asset is for. So you see when I
put a data asset here, it's going to have all
of my materials saved for the outer materials, all of
them for the inner materials, it's got my meshes as well
for the inside and the outside. And it's got my pivot textures. And when this is
working in the system, you can just pull out any
instance of this Blueprint, and this for example
is a ripple building. I could take this data
asset now, and put it in, and put it in here. And all of a sudden now, it's
just a Pivot Painter building, it's not a ripple building. I could take the data asset
for this building here and plug it in here. And now it's got a
whole new mesh, and it's just a Pivot
Painter building. It doesn't have
any ripples on it. And then I could do the exact
same thing for the ripples, so now this building has
a ripple effect on top of it as well. So then, I guess the
question now would be, how do you set these up. I think it's pretty
obvious why you'd use it. So the first thing
that you need to know is that it's a
Blueprint, so you need to right click Blueprint
class and drop down all classes and type in
data asset, primary data asset. And then you'd call this
whatever you wanted. I'm going to prefix it
with DA, so for data asset. I mean, you can just call
this building config or whatever you would like to call it. And then in here is where
you will create variables. So you will create
a bunch of variables that you are going to need
inside of your Blueprint. I've already done it for this. I created arrays for the outer
material and inner materials. Different texture assets here
as well for the pivot and rotation axes. I mean, what that looks
like inside of the Blueprint is you would create a
reference that is a variable to that. So here, I've got
building configuration, and that is just a variable
type, a DA pivot building, but I could create one now
for the one we just created. DA underscore building
config, so we've got that there. And then you just
make that public, so that you could
add it in as a variable. You can see right there. I mean, what can happen
is that you got to pull that off, so for example, so when
I'm updating the Pivot Painters, I just have a bunch
of functions that are just updating and setting
value inside of the shader. But when I want
to reference things that aren't going to change,
so for example, the building meshes and textures, so
the pivot textures, for example. What I need to do is just
pull off from my building configuration,
and I can just do, gets outer material
pivot, for example, or get outer materials. And I can reference that
inside of the Blueprint, and all of those values get set. So here, I'm doing it again
for the inner materials. I'm getting the
array that I've set that contains all
of my materials, and I'm feeding it into
this function that is just creating dynamic
material instances and setting the
material to the meshes. And it's a really optimized
way of working through this to just be able to set all
your variables in one place, and then just have one nice,
little neat container that you can just pull off
and have access to all of those variables. So when you go to
create your assets, you're going to right click and
go to miscellaneous and data asset. We're going to find the data
asset that you created, DA, we created the
building config 1. Select that, and
then you're going to have, call it, DA, whatever
it's going to be, building A. And then you come
in here, and then you have access to
all your variables here, which is exactly
for the type I created when I was creating this. Here are the predefined
variables that I had created. I mean, you set
them in here, and then you set them once as
a positive, set up it all, and then you can
just send this off to your artist with the
Pivot Painter Blueprint. And they can just
switch in and out whatever config file
that they want to get the building that they want. It's a really powerful tool. OK, and that concludes
the creating the effects inside of Unreal Engine. Thank you for
watching this webinar, and I hope to see
you again soon.