ARRAN: Yeah,
this is a demonstration of just some of the
Procedural Mesh tools that you can use inside Unreal. So it uses the Procedural
Mesh Component that you can kind of add to
any Blueprint that you're doing, and in most of the
instances that we've seen, it's kind of been used for
doing lots of kind of slicing, so there's another function that lets you break up a
mesh into multiple pieces so you can do that
kind of Fruit Ninja-style cutting items in half. So what I've been kind of
doing is doing lots of experiments with the Procedural
Mesh Component, and, yeah,
these are kind of some of the results that I've come up with. So I've ended up
using it to kind of build kind of a stylized
tree generator, so that it basically lets you create these
things inside engine, which is useful because it
means that you can actually see what it's looking like in
engine as you're building it, and it just kind of gives
you a way of kind of building these tools easier. I've always found
that this kind of stuff is a bit of a pain to do
inside things like 3ds Max and Blender, so, yeah. It seemed like a good use case
to kind of get this thing going. So what I'm going to
do is kind of run through some very kind of
easy starter content for getting to grips with
the Procedural Component and then do a bit
of a walkthrough of how these particular
assets were made and then talk about where
the plugin could go and kind of if you want to download it
and add to it, then that's cool. So am I okay to start
off with the intro content? We all good? VICTOR: We are good.
Sound good, looks good. ARRAN: Awesome,
so I'm starting off with a triangle because that is ... It's probably the easiest
shape you can do. It's kind of the basic bare
minimum that you need in order to get some geometry
rendered on your scene, and I've got this little kind
of example Blueprint here that lets you pick between a
few different kind of key shapes, so we've got a triangle.
We've got a quad. We've got a cylinder.
We've got a cone, and then we've also got
a custom mesh as well. So this Blueprint
is kind of like just that nice base starter, and it all operates inside
the construction script, right? So all of these assets
are running entirely inside the construction script, which means that you
can edit and build stuff without having to go in and
play in editor or anything like that. You can just do it
straight in the editor. So starting off with a triangle, this one is super, super,
super simple, right? All I'm doing is,
I'm specifying some vertex positions, and then I'm getting
the triangle order, and then that gets fed
into this bad boy over here, the Create Mesh Section. And all this done is it
takes in arrays of data, so we've got vectors.
We've got integers, and we've got
kind of UVs as well, so it's a vector 2D, and then it uses that array
information to build the mesh. So inside my component here, I've got a Procedural
Mesh Component, and if you want to kind
of build this stuff yourself, that's super easy.
You can just kind of go in and add the Procedural
Mesh Component as you need, and then all you
need to do is figure out where those points go
and then build your assets. So the easiest thing,
I would say, to do is actually
building your vertexes. That one is not really
that much of a problem. The thing that's
quite difficult to do or can be quite difficult to do is figuring out how
to build your triangles because you need to figure
out how to sort those things, sort that order out so
that it's drawing correctly, and that's kind of why I stuck
with the foliage aspect of it because actually, foliage,
it's all simple shapes. It's just about the placement
of those simple shapes as they kind of stack forward,
so with almost all trees, you're only ever really dealing
with cylinders and cards, and that's kind of all you
really ever have to worry about, and it can get more
complex than that. And we've got a few
demonstrations of how you can get a bit
more complex that that, but for the most part, it doesn't get past kind of
those cards and cylinders. So once we figure
out how to draw a card, we can figure out
how to draw a cylinder quite easily after that, and then once we've figured
out how to do those two things, all we have to do is
start stacking them on top of one another
until we get a tree. So my draw triangle,
again, really simple. All we're doing is, we're specifying
three points in space, so that's going to be
my vertex positions, so the first one is 000,
so zero access, and then we're doing
one of set up in 200 and one asset in X200 which gives us our two
points on either side, and then all we need
to do is have our triangle build around that, so I have my
triangles sort order. And all the integer
is doing here is it's specifying
the vector position in order to make the triangle.
So here I'm specifying 210, which is going to equate to
210 inside the vertex array, and then it will
build a triangle based on those
particular points in space. So once we have a triangle, it's not a difficult
step to build a quad, and in this case,
I want to build a grid of quads. Right? Because we can
step up from there quite easily. So in this particular instance,
I'm doing a nested loop. Please forgive me, and we
are basically getting an X length and a Y length which is going to be our,
in this case, our number of vertexes
in the X and Y coordinate, and then we're looping through, and we're adding
a vertex in X and Y, so getting these
particular coordinates, multiplying that by 50 which is going to be our
gap between our vertexes. And I'm also doing
a UV position as well, which is basically
normalizing my X length, so the max number of vertexes
that I'm going to have in my X and max number that
I'm going to have in my Y and then dividing that
by the current number that I'm on to give
me a normalized value. And that means that
when I create my material, my UVs will be correctly
scaled across the X and Y access for my grid. Now,
if you're doing a basic grid, we actually have a function built in called Create
Grid Mesh Triangles. What this will do is,
it does all of that kind of difficult triangle-calculation
work for you, so you basically
just put in the number of X and Y coordinates
that you're going to have, and then you set
the array of triangles, and it will output
those triangles for you in this particular array here.
And then we also have a function for generating your
tangents and normals, which are important for
giving you an accurate tangent and normal-facing
shape for your faces, and that's just done in the
calculate tensions for mesh, and what we need to do
there is input your vertexes and your triangles and your UVs, and then it will output the
normals and tangents for you. So all of that
stuff is quite easy. So with draw quad,
we get all of our vertexes. We get all of our UVs.
We get all of our triangles, and we get all of our
normals and tangents, and then that gets
plugged into here. So the grunt of the work
is all done in figuring out where all the
vertexes need to go and where all the
triangles need to go. Once you've got this
kind of basic information, the rest of it will kind of
fall into place quite nicely. So once we have a quad,
it's a fairly easy step to turn that flat quad,
which we've got over here ... And I can kind of show you
the Y frame of this as well so you can come see the shape. So you can see, we've got that
X and Y coordinate going in there which gives us our grid pattern. And then all we need to
do is wrap those vertexes because our triangle calculation
doesn't need to change. All we need to do is wrap those
vertices around a point in space rather than just doing
it on a single axis. So if I switch over
to this one here, you can see that that's
all we've done, right? Instead of doing it on the quad, we're basically using our
axis here as a center point and then expanding out
from that shape radially to give us our final object. So if we take a look
at the draw cylinder, we have a rotate about vector, which is how I'm doing
that kind of simple axis around our vector,
and for the X, all I'm doing is getting the
number of components again, so that's just the normalization
of X, multiplying that by 360, so I get my coordinates
correct for the 360 degrees, and then I rotate my forward
vector around my up vector. Right? So if we're thinking like that,
that's my up vector. That's my forward vector,
and all I'm doing is, I'm just twisting that round
and then putting a point in at those kind of increments
as they go around. I'd have to break my
hand to show you properly, so you'll just have
to take my word for it. And then we're multiplying
that value up by 100 because the forward
vector is still just a vector, so we want to increase the
scale of that particular vector. And then that gets
plugged into my add value, and then by Z is
actually exactly the same, so it's just Z times 50, right? Which is just my
vertical increment, and then my UVs are the same. My triangles are
exactly the same, and so are my
tangents and normals. So that basically gives
me my cylinder shape, and then once we've
got the cylinder shape, it's a fairly easy step to then modulate the
width of that cylinder over the height of that cylinder.
Right? And this is where the
cone shape comes in, so if we switch over
to this one here, like so, you can probably guess how
we're building that particular shape. So all we're doing is,
instead of multiplying it up by a single value which
was 100 in the cylinder, we're now taking into
account the normalized Z value, so the normalized
height of our cone. Sorry,
and then we're inverting it as well, so instead of it going
between kind of zero and one, it's going between one and zero.
So we add the base. That scale is
going to be at one, which we can multiply by 100, and then as that
value goes down, we can then multiply that down so it becomes smaller
until you reach nothing. Now,
this is just one way of doing it. You can also, then, multiply this by a curve
value over time as well, so you can control exactly
how you wanted to do this, or you could do it by
something like a spline if you wanted to
expose that value out and create kind of
a lathe approach. And then you can see here, all of the other code
is still exactly the same. We haven't changed.
We haven't changed any of this stuff. It's literally just changing how we calculate that
initial outward value. So that's quite a
bit of information. I don't know if there's
already questions or not or if I can carry on going.
Victor, do you want to ... VICTOR: I think you can
keep on going for now. We're collecting all the questions,
and ... ARRAN: Keep on going?
VICTOR: Yeah, yeah. We're still good. ARRAN: Cool,
so once we've got our cone shape, that's kind of like the basics
of generating our mesh data inside our Procedural
Mesh function. There's one extra one
that I want to show you which is really useful if you want to grab
anything that's more complex. So this is called the Get
Section from Static Mesh, and what that
allows you to do is, it allows you to specify a
Static Mesh that you want, and then it will output
all of that data for you, the vertex, triangle,
normal data. So if you want to start adding
in more complex shapes into your procedural generation but you still want to be
able to get the normal data or the vertex-color
data and specify that, then you can still retrieve or set that particular
data using this function. So for that final demo,
this one here, I'm actually getting a
mesh that already exists and then just replicating that to the Procedural
Mesh Component. Let's close out all those. So there's one
extra function in here that I haven't covered yet, and that's just
clearing the mesh data. So this is a really important
step that you do need to make sure you're doing as you're going through
and building your content. I've run into this quite a
few times where I forgot to clear my vertex data
and then all my triangle data, and I was trying to figure out
what was going wrong for ages. My computer was getting
slower and slower until I realized that I had just been
stacking my vertex data on top of one another until I ended up with
just an insane array size that was making my
computer very sluggish. So the first thing I do when I start building
these components now, I've learned through hindsight,
is I just build a function that clears all of
the relevant data that I'm going to be kind
of setting and updating. You might notice as well,
for the eagle-eyed viewer, that I'm not clearing
all of my data, and that's because some
of this data is set manually, so for these two data sets here,
normals and tangents, I don't need to clear that data because I'm setting
it manually in here, so it would get
overwritten anyway. So that's the very,
very quick basics of the Procedural
Mesh Component, so that gets you from
going from a triangle all the way up to a cone
which is the magical world. VICTOR: Hey, Arran.
ARRAN: Yes. VICTOR: Do you want to
go and hide the grid? We're getting some
flashy artifacts here. ARRAN: Oh, yeah, sure. Sorry. I did have that hidden,
but it has ... VICTOR: Thank you.
ARRAN: ... clearly come back. Yep. Thank you. So once we've done
those particular sets, we can start building
some more complex data. So I've got a few different
tree examples over here, and I'm going to
try not to edit them because I've got quite a lot of
examples in this project open, and if I make any
changes to anything, it's going to have to
rebuild all the trees. Now,
for this particular project, if you're interested
in downloading and trying it out,
just a few quick notes. They are all inside the
Trello plugin, the Trello doc, so make sure you go
through all of that stuff first, but just in case.
It's all inside the plugin, so you do need to put
the downloadable content into a plugin folder. It will work in 4.25,
even though we're on 4.24 here. I have tested it.
It's a content-only plugin, and none of the content that we've been
building is experimental, so it should be
reasonably stable, kind of fingers
crossed going forwards. I have run into a few issues with building out
the final asset. So one thing that I
recommend doing is actually going into
your project settings or your editor preferences and just increasing
the max-loop count for your project, just for this.
Obviously, you don't want to really do
that for any game projects because you don't want your
loops to be getting that big because you'll end up
with some frame hitching, but for this, where we're just
kind of playing around in editor and it's never going to
see the end consumer, it's absolutely fine to kind
of whack that number up. So the project itself is
a number of Blueprints which are kind of
snappable onto one another. So there's three in total. There's a trunk,
which has a base-spline component which you can kind of
go in and tweak and edit, so I'll do that on this one here
because it'll be a bit quicker. So it kind of uses this spline
shape to build its geometry. Then you can kind of go in,
and you can edit that and make it look
kind of ridiculous. Then there's a branch component,
which is built on top of that. So for this particular one,
if I just hide these leaves, there's these kind of branches
procedurally placed on top, and they can stack. Right? So you can put a
branch Blueprint on top of a branch Blueprint
on top of a branch Blueprint, and that will be fine, though you will get
into scaling issues because it will put X number
of branches on each layer of branches as you do it, so that does get exponentially
more expensive very quickly. But this will basically
take in either your branch or your trunk data,
and then it will spawn other branches along
that particular point. So you can kind of see,
I've got my trunk here. I'll just get rid of
that bark as well. I've got my trunk here,
and then off of that, I have my next
layer of branches, which I've got a set number of.
So if I go down here, you can see the spawn
count is set to five, and I can increase that if I want to,
so I get more. And then off of that,
I have more branches which are spawning
off of those branches. So for this particular one, I have five branches that
spawn off those branches. Now, the way this works
is that it's going to spawn five branches on each
branch which is, again, why it gets exponentially
more expensive as you build. And then finally,
I have my leaf layer which actually uses
the Static Mesh to build. So for this particular one, it takes in a mesh or
an array of meshes. So in this case,
I've got this little thing here, and it will then
scatter that mesh across whatever its
parent is in the hierarchy, whether that's the trunk
or the branches itself. So for this one, the leaves sit right at the
end of the hierarchy, right? So we've got eight
branches spawned across five kind of
times six branches, so that gives you all
of the kind of leaf cards that you'd need on top of that, so you can kind of
turn these on and off. And kind of the reason
why I broke this stuff up was because I wanted this
tool to be componentized, right? So you could
build multiple trees, and I could copy and paste this particular leaf setup
over to another tree, and it would just
populate that other tree. So you can kind of try this out with the plugin when you get it. So each of these sets has
a load of different setting that you can apply to it. So if I start back
off with the trunk, I've got the number of
length and radius segments that you can add to it and
how thick that branch is, so I can make this trunk
much thicker if I want to, and it would just
kind of update, and you'll see that
that information actually propagates across, so even though these
are different components, they still interact
with one another. Just going to make
that thin again. I've got some material settings,
which again we'll dive into because the material is doing
some interesting stuff as well. I actually have got a
displacement texture implemented in,
though it's still ... It's not particularly
performant, so that does still
need a fair bit of work, and then I have my references,
so you can kind of see here that this has a reference
to a parent and a root, and then it has its
child references off this, so this is how I'm
updating all of the objects inside this particular tree even though they're
separate components because they've got these
references to that class, and then finally I've got
some exposed buttons on top of this here, so it let's you add
particular components to this, so if I want to add another
branch layer or a leaf set, I can do so just by pressing
one of these particular keys, and then the same
with the branch data. I've got some variation
controls that give you some curl and some just shape controls that you can get
some nice variation, some length control for that as well,
again, spawn count, length and radius.
A lot of this data is shared, and then some location,
rotation and scale parameters to allow you to control
how those objects are doing, and if those objects
have a parent, then you can modify
the range of that as well, so for this particular one,
I have a parent range, so it basically clumps
the spawn location for all of those branches,
so at the moment this is at 0.4, so the branches
only start spawning about halfway up the tree, but I can have that
happen way lower, so if I set this down to 0.1,
then these branches will start spawning much
lower down on the tree. Actually, it looks quite good.
I quite like that. Anyway,
let's pop that back up to 0.2 just so we don't
get any clipping, and then finally on
the leaf component, that has again
very similar data. It's got location,
rotation and scale, and my location
has gone up there a little bit for some reason.
It has its references as well, but what it also has as
well on the mesh side is an option to
render as instances. Now I added this as I was running into
some performance issues because this is running
all on construction, and that loop count
can't get quite large, which means that you can end up with a fair bit of
pausing and freezing as you're tweaking and
changing those values, so I've got this
brilliant option here. You can see it kind of
stops the foliage from moving. Let's go back to that,
but this is really useful because I can actually set
my spawn count much higher without having to worry, so I can set this up something
like 100 or something. That might have been a bit high,
but I can set it ... VICTOR: It looks great.
ARRAN: It looks amazing, doesn't it? VICTOR: That's the alien world,
right? ARRAN: I think my computer
might be dying. It might by dying. I'm just going to
knock that down a bit. That might have been a bit mean. VICTOR: Take everything
by 30 percent less because this already eats
up 30 percent of your GPU for streaming high quality. ARRAN: The stream
has already tanked, but yeah, so I can control that,
and that's really useful if I want to just see
what it looks like without having to worry
about it having to recalculate all of that geometry
every single time. What did I have it on before? I'll just put it back
to six just so it's ... Keep it reasonable just
for this stream, so yeah, and that's the basics of it, so I've got these
individual components, and then I can slap those
onto one another just as I need, so let's open up the Blueprints and let you take
a look at those, so I go back to my
construction script, all my construction script
does is run a function called Draw Me, which is how
all of that stuff is calculated, and Draw Me is an
exposed function as well, so you can call this manually, and that's actually how
the updating children works, so if I go into the
Draw Me function and call Update Children,
you can see that all it's doing is it's getting those
child references and then looping through
and telling them to redraw, so it's telling them
to call Draw Me, so even if you're editing one
step lower in the hierarchy, it will work,
and again this is another reason why I can broke these up
into separate components because I didn't want to
have to redraw the entire tree if I was editing things that
were higher up in the hierarchy that wouldn't get affected, so the benefit of having
this broken up, again, is that I can edit
my leaf Blueprint, and it won't have to redraw
any of this stuff underneath because none of
that data has changed, so if we go to my construction,
my correct Blueprint, you can see I'm
calling that function, that first thing that's clearing
all my data that I don't need, so in this case,
I'm clearing all of this stuff. And then I build my branch data,
which is this thing, and all I'm doing here is I'm checking to
see if there's a parent. If I have a parent,
then I need to modify my workload because I need to account
for the fact that we've got ... It could be just a single
trunk that these branches are spawning on,
but it could also be the case that it's spawning
across multiple branches, and at that point I need
to be able to identify that, so the parent will
get identified first, and then I have this thing
called my tease array, which is basically just an
array of transforms and scales which will allow me to
get that particular data, and then I look through,
and I build all of my branches, so all of this stuff
in orange here, that's just figuring out the
spawn point of my branch, so as I'm building this ...
Let's just hide these, so what I'm doing is
I'm finding my parent. In this case, it's the trunk, and I'm grabbing
the transform data, the transform array data,
of this thing, of this trunk, and then I'm scattering
spawn points onto that based on data that I'm setting, and then once I have that transform,
I can make my branch, so all my branch is doing
is again it's figuring out where it needs to spawn,
so using that base location, and then it's
drawing that radius, so if we go to the radius,
that's going to look the most similar to you as
we were looking at before, so that's where we're
building our vertices and building our triangle data and then also building
our UV and our vertex color. I am working on getting
Pivot Painter working as well. That's still a big of
a work in progress, so you'll see a lot of
stuff on Pivot Painters that's just tucked away.
That's not working yet, so you'll have to wait
for that one I'm afraid. I need to get some more
help with Jonathan Lindquist to get that one working I think. So once we have our branch data,
we can create our mesh, so again that one
is quite simple. All we're doing is
we're grabbing that data that we've calculated, and we're feeding that
through to the mesh section, setting our material for
that Procedural Component and then setting that
to this standardized data set that I'm using
to pull data back and forth between lots
of different Blueprints. It's probably going to
be a little bit easier to see, so this is the trunk script, so what I'm doing here is
again it's the same thing. I clear that data. I calculate my segment distance,
so this is going to be the scale that I'm going to be
offsetting along that spline, and then I do the ...
If you've done anything working with spawning
stuff along splines, then this will be
fairly familiar to you. All I do is I find my
points on that spline, so I get the transform
at that distance, and then my draw radius
does exactly that same thing as we were doing
with the cylinder, so we have our radius
segments over there, and we just go through,
so again getting my vertex data, getting my triangle data, my UV data and
vertex color data. And then for my leaf, I think this one is actually
the easiest one of all because we actually don't
need to do much of that calculating the mesh
because I gives it to us, so all I'm doing here is I'm getting that
mesh array variable, which just defaults
that to this cube here, and it gets that triangle
data and vertices data, all that good stuff, and then it sets it
to a data collection, so I'm just grabbing all
of this information here. And then I can go through
and build that mesh, so again clearing my old data
because I don't need it anymore, finding my parent and finding
the transforms for that parent, so this is my tease array here, and then I have to do
that nested version again because I might
have multiple branches that I need to spawn across. Then I figure out my location,
exactly the same, and then go through, and this is where I've
got the branch here, so I can choose between
rendering instances or rendering the
mesh calculation, and the mesh calculation is,
again, it's doing pretty much
the exact same thing except in this instance
I'm offsetting my vertex data so that I can
stack it all together, and that gives me
the tree component, so if you're going through building some
of this stuff yourself, the hardest thing to
actually get working is stacking this data so that it works with
the Create Mesh section, so in order for this
to work properly, you need to be able to
offset all of your data correctly, and this is why the
Create Grid Triangles doesn't work,
so the grid mesh triangles, because this needs an
offset in order to work properly, so this data output
doesn't work, so you actually have to
build that function yourself when you're going through.
Now I've built it so you can technically
just grab it from here, so if we go to my branches
and go to my construction script and make my branch
data and drop my radius, this is the function
that basically does that, so this is all I'm doing. It's really, really dumb and really,
really simple, so all I'm doing is
this is creating a quad, so this is my first triangle,
and this is my second triangle, and yeah. It's pretty simple, but the main reason
why I had to build that was because I need
that initial offset because otherwise
the triangle data won't match up
with the vertex data that you're trying to build,
so just keep that in mind when you're trying
to build your content. And that's the basics of it,
so we can go into a bit more detail into
how this stuff works. I can give you an overview
of the upcoming features of the things that I ... VICTOR: Can we tackle a
couple of the questions first just to sort
of go over ... ARRAN: Yeah, absolutely.
VICTOR: Sweet, sweet, sweet. So in general there's a little bit of
conversations in chat around ... So specifically for trees,
what's the specific use case for doing this in-engine,
and could you maybe also talk a little bit about
the possibilities? Why would you do it this
way instead of using Houdini or just model the
trees yourself? ARRAN: So absolutely. You can do
it any way that you want to do it. There's no reason why
this is any better or worse than the other tools available,
so Houdini is great because you can export
that out to an engine plugin and then bring that into engine. The main reason
why I built it in here is so that I can
see the content live so how it's actually going to
finally look inside the engine, so if you're building it inside something
like Blender or 3ds Max, then you have to
approximate what you think the tree is going to look like,
and this is quite difficult because 3ds Max's viewport
especially is not very good at rendering this kind
of geometry in real time, so it's quite difficult
to get an appreciation of what this tree is actually going to look like
until you've actually done it, so on the building
it manually front, you've got that as an advantage. It also takes a
lot of time as well. This stuff is quite annoying
to build because the tool set doesn't really exist to make
these trees particularly nicely. You have to go through
and do a lot of finicky work and a lot of cleanup in
order to get it working, and this plugin will do
a lot of content for you, so if we take a
look at this one here, this actually an exported mesh, and one of the benefits of
doing it this way is that you get all of the vertex color
assignment done for you, so for this particular tree
if we look in the paint view. Don't want that one.
Give me red. So I've got a red channel,
which is a gradient that works outwards from the radius
of the base of the trunk, so what this will do is it allows you to
control the wind strength if you're doing anything
of that stuff in shader, and then in green,
I've got another variable that will color these
outwards from the spawn point that they're coming from, so you can see
that starts black, and then it comes out to green,
and then I've got a blue channel which gives me a
random color gradient, and this stuff is really
difficult to do inside something like 3ds Max.
You'd have to go through and manually repaint
that stuff for you, so that's quite tricky,
and then going through and actually painting
these foliage sets on and seeing how it looks
is quite a pain to do, so ... VICTOR: And if you have
30 different trees, you have to redo that, right? ARRAN: Yeah. Yeah. Absolutely, so you'd have to
go through and manually edit it, whereas with this one
it's all seed-based as well, so once I've made my
tree and I'm happy with that, I can export it,
and then I can duplicate it out and then do it where I could
just make a new instance or a new seed off
of that base data, so I could go in,
go to my random seed and then just change this value. VICTOR: And so there are
essentially two different use cases for this. One is to actually
export it as a Static Mesh, and that's possible with the tools,
right? ARRAN: That's the only
really intended purpose. You'd always want to
export it out as a Static Mesh. VICTOR: What you could also
do is essentially modify that run time,
which is something that you wouldn't be able to do
with a pure Static Mesh, right? ARRAN: Yeah. Absolutely. VICTOR: Just talking a little
bit more in general about the Procedural
Mesh Component and the idea of why you
might want to use that for other purposes
than just trees, so in case you wanted it to
grow in very dynamic ways that you can't really do with
bones or vertex offsets, etc. You have that power
prior to exporting it, right? ARRAN: Yeah. Absolutely,
so the Procedural Mesh Component works in-game as well
as at the editor level, so it would be work, but it would be reasonably easy
for you to take this base code and have that run over a tick so that your tree was
growing over time, so you kind of
start at that trunk and then build out into branches
which build out into leaves, so you could definitely
build this as a procedural tool, and there's lots more that
you can do with this as well. One of the other benefits of
it being built inside your level is that you can expand
this tool set so that it works. It takes into account the
world around it as it's building, so if you wanted it to build
up against the side of a building or the side of a wall
or something like that, you could add line
traces in to do checks and let this thing grow out
a little bit more intelligently rather than how it's
doing at the moment which is just based
on random data. VICTOR: Let's do a few
more of the questions, and then we'll dive into
the rest of your presentation. makuzmakuz asked,
"How preformative is this?" and then the
follow-up question was, "Is it possible to regenerate
the object every frame?" ARRAN: In terms of performance, it completely depends
on the size of the asset that you're building.
If you're doing it every frame, yeah, it does completely depend on how big a mesh
you're trying to make. You can see even when I
was rendering this as instances it took quite a while
for it to process it, so as you're getting up to those
large-scale objects like trees, you might run into
performance issue as those things get larger. VICTOR: As it does
when you're playing with a lot of
instructions at one time. ARRAN: Yeah.
It's all about how many loops you're going through
to build this thing. VICTOR: Ylly was asking, and I'm
not entirely sure what this is but, "How to set up a
custom vertex factory?" ARRAN: Yeah.
I don't know what that means either. VICTOR: I'm not entirely sure. If you want to go
ahead and clarify that, we'll try to answer
your question. TLuisRS asked, "Is the Procedural Mesh
Component still experimental?" ARRAN: Oh, I need to double-check.
I don't think it is. VICTOR: I think it might say
in the list of plugins. ARRAN: Yeah.
It would say on the Docs page, so you could have
a look at it there. VICTOR: TLuisRS also asked,
"Is it possible to generate different LEDs for procedural meshes, or this is handled
automatically by the engine?" and I think we can dive
into that a little bit of sort of how you would ...
We touched on it briefly, but how would you
go ahead and do that? ARRAN: Yeah,
so for this particular instance when you build out your
Procedural Mesh Component, it's only making
one Static Mesh. I've got a billboard component,
which has just gone white, but that actually does the demo of how you can also
generate a billboard for it, which you could then
export and then assign that to be allotted for
that particular instance, so you can see this
version here is just a Static. VICTOR: Impostor! Very sus. ARRAN: If I just take that,
leave it off to the side, so this is doing a live capture,
which is why it's moving. You obviously wouldn't
get that in the captured view unless you stored
it as a flipbook, but this will do a
capture to a card, which you could then do it,
and you could also use this to pair it with Ryan
Brucks's OpTree Capture to give yourself
more faked-3D sprite for this particular effect. VICTOR: And then Onnion_dev asked, "How do you deal with duplicated
vertices when stacking meshes?" ARRAN: I'm not sure what
you mean by that either, so do you mean when
we're spawning multiple meshes like I've got here? I've got 12 instances
of the same mesh? I'll just assume that,
and then I'll answer that one, and if that's wrong ... VICTOR: Go ahead and with that. Please let us
know if it's wrong. ARRAN: ... we'll find out,
so the way that this works is that it gets the base
data for that particular mesh, so in this instance it's
this palm frond mesh type, and it gets all of the
vertices and triangle data for that particular asset, and then when it
wants to make them, it will use the transform
of the spawn point to offset those vertices and
then add them to a new loop, so inside my Make Mesh,
this is getting my transform, so I figure out where I want
to spawn my palm frond, and then once I've got that,
I can use the transform location from that base to offset
my vertex spawning, and that then gets added
into my new vertex count, and the way that that avoids,
they don't overlap. They have to basically
add one on top of the other, so my array has to
store the vertex data for every single instance
of this particular one, so it will go
through each count, and it will do it
each time for that, so here I'm getting the
vertices for this particular mesh, and then I'm looping
through and transforming it, so it's transformed
to a new position, and then that gets added
to the new vertex data, and then I have to do the
same with my triangles as well. So that's done here, so I get
my triangle data from my mesh, and then I have to add
it including the offset, so this is where it
gets to be a bit of pain because you can't just ... Otherwise I could
just duplicate this data, and it would be much easier,
but I can't do that. I have to account
for the offsets as I'm storing it
into a single array. VICTOR: Someone else asked ... ARRAN: I hoped that
answered the question. VICTOR: If it didn't,
please let us know. ARRAN: Yeah. VICTOR: Someone else asked,
"Would this be a reasonable method to use for foliage
in a large area, or should this be limited?" ARRAN: So you should use it,
if you use it at all, to generate single assets which
you convert to Static Meshes, and then once
they're Static Meshes, they're the same as any other
mesh you'd have in your game, so you can use them
however you want, so for some of
the image content, we had that island scene, and that's built
entirely using ... All of the foliage in that
is built entirely using this, so I build each component. I export them out,
so you can see my palms. I've got a few
different examples here that I've gone
through and created, and those are all just
normal Static Meshes like anything else. VICTOR: And then you can
use the autoLED tool to generate new LEDs? ARRAN: You can. You can. Yeah. You could use it
to generate those, though I don't think it
generates a card in this unless they've updated that,
which would be awesome. VICTOR: All right.
We have a few more that came in, but why don't you continue with what you were
planning on continuing, and then we'll get
through questions that are coming in later on.
Okay? ARRAN: Oh. Okay. VICTOR: And I'm still
going to be live, but I need to go
mute my fire alarm that's been beeping
for the last 25 minutes, so please go ahead, Arran.
The floor is yours. ARRAN: Sure, so I've got a load
of these examples here, and this stuff can
look really complex, but the main thing that
you've got to keep in mind is all it is this data. It's just these quads and
these cylinders just stacked on top of one another, so I think the main thing I want
to get across is even though this might look like it's really
complicated, all this stuff. This looks terrifying
spaghetti code, though I have tried to clean
it up as much as possible. I'll just move that out the way. All of this stuff is still doing
that same base component. It's just figuring
out its vertexes, figuring out its triangles, figuring out its UVs
and its vertex colors, and then it's passing that
data through, so I would ... If you're interested
in trying this stuff out, just take it one bite at a time,
and you'll get through it. I promise, so next up I
wanted to cover the materials, so for this, I'm heavily using
the material instances feature, which is really useful
for this kind of data, so I have my base
tree type here, and this script
basically represents every single material
type that you've got here, so for absolutely everything, and it gives me quite a lot
of power in what I can do, so I can choose whether
this thing is masked or opaque. I can choose
background and two-sided tinting, normal data,
and most importantly getting some reasonably nice foliage
wind for this particular object, so you can see
I've got this little, wobbly, animated ball,
and this is my base type, so when I'm going through
and creating a new tree, the first thing that I do
is create a new instance off of that kind of base parent, so this kind of base material,
and then from that, all of my other kind
of material types that I'm using inherit
from that instance, right? So we have a
hierarchy of instancing, and what that means is
that I can share my wind data across all of my instance types without having to redo
it every single time. So if I open this one up again, you can see I'm kind of setting
the parameters, pardon me, for my leaf wind and my
wind layer one and two. And this is all derived
from a custom function that I've built
called Tree Wind, which basically lets
me kind of turn on and off these
particular functions, so I've got some static switches,
as well, which lets me control
the particular strength of whether I use
each of these layers. And then I set up
these parameters on that kind of
base-material instance, and then from there,
I inherit from that, and you can see that this data, I'm not overriding
with anything. It's just kind of being
left as its original, and then all I'm doing
is overriding my data, so I set my diffuse texture. I set my normal texture.
I set my opacity mask texture, and then I override
my material properties so that it's masked
rather than opaque. It uses the two-side
foliage model rather than the default lit, and it's listed at two-sided,
as well, so I get it two-sided. And that way, even though
I've got a really different material for both of these
particular types, it's using the same
base material parameter, and the way that that benefits it that I get that kind
of propagated data, so that's all kind of really,
really useful stuff for me as I'm kind of going through. So the wind itself is
again quite a simple thing. I'm just using
world position offset. It's not doing any of the kind
of smart Pivot Painter data that's one some of
the other examples, so if we kind of open that up,
I can show you that material, just open up that tree
base and open up tree wind. You can see that it's
just feeding straight into world position and offset, and I'll start with
wind layer one. So I have the
texture sample here, which is just some kind
of simple turbulence, and that's in world space,
and it pans, so that gives me some kind
of nice kind of cheap noise that's kind of moving
through the world, and what's also nice about
this is because it's world space, when I place my
trees around the world, it'll have that kind of
unified wind movement that kind of moves through it. That gets multiplied by a
wind-direction parameter, which is basically giving
me a vector direction, and then that kind of gets
multiplied by the alpha, which lets me control the strength of
that particular value. And then that gets multiplied
with a power of to kind of give me some
control of the fall off by the vertex colors
green channel. And then inside my blue channel,
that's my random variation. I have kind of an offset to that,
as well, and that gets multiplied in. Now my finally parameter
here is the red channel, and that was that
gradient that you saw, and what I'm doing
here is I'm kind of using that red channel to control
the fall off of the wind, so at the kind
of the base trunk, I don't want any wind
movement at all, right, because the base of the trunk
shouldn't really ever be moving unless it's been uprooted, which we're not
accounting for in this. So I use that gradient that
I have created for the tree to control the strength
of the wind over time, and then I use the green channel
and the blue channel to allow me to control the turbulence
that we're going through here. So you can see my kind of
leaf-wind layer one and two. That's using that red
gradient to control the strength, and then as I move to leaf wind, I'm accounting in for
some extra turbulence, which uses that kind
of green gradient. So if we go back onto here
and just do the color preview, you can see that gradient again,
so we have that black to red, which gives me kind
of the base wind control, and you can see that
some of these things are just rendered in black, and that's because I don't
want any of that kind of wind movement on
it at all to start with, so these little kind
of bark-peel meshes are rendering in black so that they don't
kind of animate. Then that green channel
is controlling the leaf, so you can see that's kind
of where this comes in here. We have that kind of leaf-wind
property, which we can control. And then we have
our blue channel, which gives us that
random variation, and you can see that's
kind of coming in here, and that's what gives
each kind of leaf instance or leaf-mesh instance
its own turbulence, so you can get some
nice variation there so it's not kind of repeating
every single time you have it. So you can kind
of see on that one. You get that nice
kind of variation, so it doesn't look like every
single leaf is moving in tandem. It looks like they're each being impacted by their
own turbulence. Now, this is reasonably nice, but as I said,
it's not the same as Pivot Painter, so you don't get the
advantages of Pivot Painter, which is that kind of
individual movement. That is something
I'm working on, and if you're interested in checking that
particular element out, you can go to the
root Blueprint tool where I'm kind of working
on that particular type. So this script is basically
running through and grabbing all of that stored data that I'm building as I build
each of my components, and then it builds a
Pivot Paint texture, which I've got an
example of in here, so if we just zoom in
to this little texture here. This builds a 16-bit
location for my pivot points, and then this forward
vector builds a vector position, so in theory, I should be able
to render out these textures and use them to generate
the Pivot Paint material data. But as I said, I'm still working
on getting that one working, so it's going to
take a little while. VICTOR: You've come
a pretty long way, though. I did find your
article from 80.lv. I should share that,
as well, if you're interested. ARRAN: Yeah. So go on.
VICTOR: I was going to say, if anyone is interested
in being able to share this in a little bit more
concise form, there's also an article
that Arran wrote for 80.lv. I'll go ahead and paste that. ARRAN: Yeah. The article
covers all of this stuff, right, and it covers it in a way
where you can probably digest it a little bit more easily. It kind of goes through
each of these steps, so same as kind of
building that triangle, quad, cylinder and cone,
and then it kind of goes on to explain how some of
this stuff works, as well, so you can kind of go through
and build that stuff yourself. And, yeah,
that's kind of the big stuff. I'm happy to go through
some other bits again. I realize we kind of ran
through that particular stuff, so we can re-cover some
bits if there's any confusion, and I can answer
some more questions. VICTOR: flowerhat had asked, "It was mentioned turning
these into static meshes. Do you have to export
them first and reimport? Also,
do they keep all the vertex data that you'd shown earlier?" Perhaps could you
show the export workflow? ARRAN: Yeah, absolutely,
so that's a great question. So the root, which is why
the Blueprint is called Root, of each of these trees,
I have kind of a base component, and what you do in here is
you specify the components that you want it to build, so here I'm specifying
kind of the trunk and the palm bark and fronds
that are coming off of that. And then you press the
collate and build button, and what what will do is it will build a
single-mesh version, so it takes all of these
individual components, gets all of the data for them, and then it rebuilds all of
that data into a single set and optimizes it.
So I kind of had envisioned that there might be
multiple instances where you'd use
the same material, and I wanted to make sure
that that would still work, so even though I've got two
separate components here ... So let's just turn on these. So these two components
are both different, but they use the same material,
right, so they need to be collated
into the same instance. So in order to fix that,
I have to go through each one, check to see if the materials
are the same or different, and then I can build
a different index. So once you've pressed
that collate and build button, we've got our
single Static Mesh, and then you can click on the
Procedural Mesh Component and press create Static Mesh,
specify your location. So I'm just going to drag
this to my content folder, example_live, and then you press okay,
and that's it. It's done it. VICTOR: And that's just
the built-in function in the Procedural Mesh
Component itself, right? That wasn't anything
custom that you implemented? ARRAN: Yeah. No, I haven't done
anything to make that happen. That's all done
inside the script, and all of that data is shared, so you can see all of my vertex
colors information is preserved. I get some super
funky trees from that. VICTOR: There you go, ship it.
It's done. ARRAN: And then you can do
whatever you want with it, right, because it's just
another Static Mesh. This is now a UAsset,
so like Victor said, I can tell it to generate lots,
if I want to, so I can tell it to do some custom or
generate it some other way. I can change these
materials if I want to. I can drag it into the scene. I can drag lots of
them into the scene, and there's no
performance issues with this at any point right now because these are just normal
meshes just like anything else. VICTOR: You can pop them into
the foliage tool painter and ... ARRAN: Yeah, absolutely. So we can go into
the foliage tool, just drop them in and
then paint them out. VICTOR: As you can see,
though, it runs just fine. ARRAN: Yeah.
Once you've kind of got it out, it's just another Static Mesh,
right? So it's not having to calculate
anything live or at any point. It's just another mesh,
just like any other. VICTOR: Marc_J asked, "Could this
be used with Quixel Megascans to make your own tree assets?" ARRAN: So yes, absolutely.
I would add some caveats into that though that
this is more aimed for kind of stylized
foliage generation, and the reason that it is that
is because it can't support, or it gets very
slow very quickly if you're dealing with
very dense geometry, so very complex geometry, so the Quixel assets tend to be very,
very high detail, which means they're
super high-quality, but if you kind of took the leaf
examples that they have in there and used that to
build your own tree, then you would probably find that you'd run into
some performance issues quite quickly if you
were doing it that way. So that's why this is
kind of more intended as more of a stylized tool where the geometry count
can be kept kind of relatively low. That being said, the materials, you could apply them
to any of these assets. It's just because you're
just making another material, but in terms of
actually generating kind of more realistic assets, this is probably not
the best way to go, and actually, you probably wouldn't want to
build these in this way anyway because it's just
using randomized data in order to get it
to kind of look right, whereas if you wanted to
build really realistic trees, you probably want to do
some kind of simulation where you're getting the kind
of slightly more accurate result. VICTOR: You could still use
some of the textures and mixer to sort of
stylize the textures. ARRAN: Yeah. All the materials
would be absolutely fine because again the complexity
doesn't come from the material with this particular thing,
right? I could swap this
material out with anything, so if I had a
realistic palm frond or even a stylized one that
was built in Quixel Mixer, I'd just apply that just like I'd apply
anything else in the world. VICTOR: Nice. Well, since that was sort of
the end of your presentation, we haven't gotten too
many more questions in chat. We have a little bit more time, so if you have any
other questions for Arran, please let us know.
But until then, is there anything else in
sort of the evangelism world that you want to share
with the audience? ARRAN: Sure.
So on the evangelism side, we're kind of scattered
all over the world, and we're here to kind
of build cool content that kind of shows off what
you can do in the engine but also to help developers
kind of with their projects that they're
currently working on and just kind of helping them
navigate the Epic ecosystem and help them out
in any way we can. So if you're not in contact
with your local evangelist, then I would
recommend you do so. If you're an indie developer
and you're working on a game or you're working
on a cool project, you should get in
touch with either me if you're in the UK
and Ireland or with all the other evangelists
that we have over there. If you go to the
Unreal Indies section, we actually have a list
of all of the evangelists who are kind of operating
and where they're operating, and you can e-mail the
Indie Evangelism e-mail address, as well,
and basically say, "I'm in this region.
Who can I talk to?" And you'll get hooked
up with the right person. We're really useful people
to know a lot of the time. We almost all have
very techy backgrounds, whether that's on the art side or whether that's
on the code side, so we can often help not
just with that kind of ecosystem navigation but also with any kind of techy,
dev question, so if you're kind of
banging your head against a particular thing and you want to talk to someone,
then you can talk to us, and we'll try our
best to help you out. VICTOR: Yeah, and that also comes
especially when it gets time to ship your game. There are things that you
might not have come across until that point sort of in
terms of finding a publisher, all kinds of questions
in terms of royalty, which at this
point is fairly easy if you're a small indie studio
because you need to make up to $1 million before you
owe Epic any money. But even then, there might be questions,
and we want to help you making sure that you
can ship your games, not only develop them
but also ship them. That's an important
step for all of us, and so the evangelists
are a great resource that you can reach out to
in terms of those questions and just awesome
people in general. I know I've had a few of
you here on the livestream, and I hope there will
be more of you to come. I know I have one planned
with Sjoerd in a couple of months. ARRAN: Oh, that's going
to be a good one, I think. VICTOR: Yes,
it is going to be a good one. No spoilers.
Anyway, let's see here. ARRAN: I'm just going to zoom
in on my mushrooms. VICTOR: Well,
I didn't actually see them. They're fairly new to the project,
right? ARRAN: So they're not actually
in the downloadable sample. I need to update it so
that they get added there, but it's one of the benefits
of just using a mesh, right, is that I can throw any
mesh I want in there, so I built just a little
mushroom in Blender and then threw that in, and then I did a little bit
of scattering underneath, so these are kind of two
separate components, so I can kind of exclude them, move them away
if I don't want them, and then these get kind
of scattered onto that mesh. I'm working on a few extra bits,
actually, so this is probably
worth mentioning. VICTOR: Yeah, show us. ARRAN: The leaf tool,
I'm also working on a scatter tool, as well, so this kind
of tree is actually built using not the leaf component
but the scatter component, so the leaf component
is used here, which generates a shape, and I'll just get
rid of this material so you can kind
of see it a bit better. Ooh. It's having a think. VICTOR: Oh. Having a think.
ARRAN: There we go. So this is using kind of
these little meshes here, which I wouldn't actually
include in the build, but I just use them to
create volume and shape, which I then use to
scatter these cards over it. And then these cards have got some different
properties on them, so I've got kind of my
base input going in here, and then I can specify
how many I want, so I'm scattering 1,000 cards
across all of these leaves, and I can change kind
of the world axis, as well, so if I want this to be
a specific axis only, I can switch that out,
see what it does there. Or I can change it to just
be local and let that build. VICTOR: Speaking of ... ARRAN: So it's using all the
same kind of base stuff. It's just using some
extra properties to kind of build some stuff, so I'm kind of tinkering away
at different bits and pieces to try and make this a bit
more useful to more people. VICTOR: Not bits and bobs?
ARRAN: Bits and bobs, as well. VICTOR: All right then. Speaking of
the sample, flowerhat is asking, "I was able to get the
project file of Trello, but how do I get
it into engine?" Could you walk
through just real quick how to use the project file
that is available for download? ARRAN: Yeah, sure. So all you need to do is
make a folder in your project. I can do it over here,
tree_gen_demo, and this one is actually
nested a few times by accident because I kept on
unzipping it into it, so you only need to this once, but you make a
folder called plugins inside whatever project
you want to put this in, and if you want to
it into the engine, then you can put it into the
engine plugins folder, as well. And you basically just export
the .zip file into this folder, and so it'll go to there. And then you get
your tree_gen folder, and then inside your plugins,
you just need to enable it, and you might
need to restart it, though you shouldn't
have to in theory, but you might
need to restart it. And then once you've done that,
inside your content folder, you'll get a plugin folder
called tree_gen_content. You might need to enable
your show plugin content for that to work, and sometimes you also need
enable show engine content for it to work, as well,
so if it's still not showing up, turn that one on, as well,
and see if that works. And then inside
tree_gen_content, we've got the example map, which is this map here which
has all of the kind of examples that you can use to kind
of start picking up the tool. Inside example, I've got all
of the kind of the static meshes that you can use, all the kind of textures
and meshes that I've built that you're free to
use however you like. And then inside the components,
that has all of the Blueprints to kind of get all of this, that kind of consist
of all these bits, so the tree parent has the
kind of base Blueprint type that all of these things
are instanced off, and then you've got branch,
leaf and trunk, which are kind of the Blueprints
that we've already covered. You won't have
scatter in there yet because that's not been uploaded
because I'm still working on it. And then all you need to do when you want to start
building your own tool is, you just drag and drop
this root Blueprint type into whatever project
you're working on, so you won't have anything
show up straightaway, but you do get these
buttons when you click on it, so you can then add a trunk, and that will
give you this trunk that you can then
start working from, so you can kind of
start building this up, and you can kind of scale
up and down as you want to, as well. So you can kind of start
building these cool things. And then off of that,
you can then build a branch, and you'll then get branches,
as well, so you can kind of see these
branches have spawned here. And then you've got all the
different properties for that, as well, so you've got how
many branches you want to spawn, whether that's eight or
three or two or however many, and then you can control
all of the parameters for these particular ones, so a nice, simple one to get
started is rotation per index. I always recommend
setting that to 137. That should be the basic number, and that will give you nice
rotation around your branch, and then you can also do
your rotation along parent, as well, so this will ...
Sorry, let's not do that. Let's do some minus 60, and
then I'll set my range up, as well. So that lets you kind of control
how these branches are spawning and the angle
that they spawn at. Let's see if we do some 0.9.
Okay? So you can see we
get these nice branches, and then we can
increase the length of them. Let's increase that a bit more,
something like that, and then what else can we do? If I increase my number
of length segments, we can add some curl to it,
as well, so if I start putting some
numbers into these curl values, you can get some kind
of interesting shapes and patterns appearing. VICTOR: So I think it's
worth perhaps clarifying that it is a content plugin
and not necessarily a project that is available on
the Trello for download. ARRAN: Yeah.
It's just the plugin file, and the plugin file will
give you all of this content. So you can add it
onto whatever project you're currently working on. It's just a plugin, and then
build your foliage as you need. VICTOR: That's super neat. That's a really nice way
to share assets like this because it is
just like you said. You can just use the
plugin inside your project. You don't actually have
to merge or migrate or do any other form
of asset migration to take assets from
one project into another. ARRAN: Mm-hmm. Yeah, and if you put that
plugin into the engine folder, it will just be there for every
project that you have that uses that particular engine version,
as well, so that's really nice if you just have
anything like this where you might want to
use it across multiple projects. You can just have
the plugin work, and anything you
add to that plugin, it will again propagate
to all of your versions, so it's quite useful for that. Created a bit of a
monstrosity here. VICTOR: Works for me.
There you go. ARRAN: That's [INAUDIBLE].
Call it a tree. There we go. Done. VICTOR: Ship it. Let's go ahead and go
through the two last questions, and then we'll
wrap up the stream. BobsDefinitelyNotYourUncle asked, "How far can you see
this tool going in the future? How far will we be
able to push it in creating even more procedurally
driven scenes?" ARRAN: So this tool was
created as just a bit of an experimentation for me. I was really interested to see
what kind of procedural content I could build,
so in terms of updating it, this is definitely a
pet project of mine. It's not an official
Unreal project that's going to be shipping
with engine versions or anything like that.
It's just a bit of fun. That being said, I'm going
to try and keep working on it and keep adding to it, so if you've got any
kind of feature requests or anything you'd like to see or if you want to do some
work on it as well and add to it, then that would be really cool. I might push this to
Git and make it public just so people can sync
it and makes changes and things like that, so,
yeah, it's a personal project, but it's a useful one if you want to learn the
Procedural Component and kind of pick
up that kind of stuff. VICTOR: BobsDefinitelyNotYourUncle
asked another question: "Could you use this
tool to benefit early block out of level in some way, perhaps in order to create
more varied, dynamic block outs?" ARRAN: Yeah, absolutely. Again, you could even
use it as a way of just quickly making the right-sized
placeholder meshes, and it would work fine for that. It is literally just a
way of generating these kind of stacked
meshes more quickly, so yeah. VICTOR: And with that,
we are going to wrap up the stream, but not just yet because
I have my little spiel that I go through at
the end of every stream, and, Arran, you're going
to have to sit through it just like all my previous
guests before us. ARRAN: Yay. VICTOR: If you're watching from
the beginning of the stream, thank you so much
for hanging out today. We hope that you've
learned something, even perhaps you
knew almost everything, but perhaps you
learned something. If you are new to Unreal Engine and you would like to get
started in game development, go ahead and go to
www.unrealengine.com, and you can download
the Epic Games Launcher, and from the Launcher, you can download the latest
version of Unreal Engine, and there are plenty.
I should remember these stats, but I think there are
160 hours of content on Unreal Online Learning.
On Unreal Online Learning, you can find courses
related to different aspects of developing games and
other things in Unreal Engine. You can go ahead and sign up
and then start teaching yourself through the help
of our instructors of how to became proficient
at using Unreal Engine. And oh, look at us, now there's
two of us in the stream room, but I do know that
Arran wants to see me while I'm just
sitting here talking. No, no, no, you're good.
You're good. You're good. I can just go ahead and
close your stream down if I'm able to, apparently not. Stop watching,
there it is right there. Apparently, that doesn't work. Anyway,
it will have to be doubled. We don't have any
in-person meetups going on in the world right
now because of the pandemic, but that doesn't mean that the
meet-up groups are not active. If you go ahead and go to
communities.unrealengine.com, you can see if there's a meet-up
group close to you in your area, and some of them are throwing
virtual events on Discord, which is nice to join,
get an opportunity to talk to fellow devs
potentially in your area, see what they're working on. Some of them even let you
do your own presentation. At least, that's what we
used to do back in Seattle. If you do not have a meetup
group close to your area, you can go ahead and--
blah blah blah... refuse to talk now. You can go ahead and hit
the Become a Leader button, and with that, you will fill
out a form that goes to us, and we will check it out
and then potentially help you spin up a meetup
group in your area. We all hope that this
is going to be over, and then we can all go back
into seeing each other in-person and talk about these
amazing things face-to-face rather than virtually like this. Perhaps we'll even be back in
the livestream studio one day. That would be nice. If you have seen us
from the beginning, we do a community spotlight
as well as our countdown. These are assets that we
find around the community, but you can also go ahead
and add us on our forums, on Twitter, Discord, unrealslackers.org,
great Discord community. If you are new to the community
and you would like to talk to more devs little
bit more broadly, globally other than specific to
the virtual community groups. The community-- Sorry.
The countdown video specifically is 30 minutes of development.
Fast-forward that into 5 minutes and send that to us
together with your logo, and you might go
ahead and be featured at the beginning
of our livestreams. If you stream on Twitch, make sure that you use
the Unreal Engine tag as well as the
game development tag. That is the best way to
showcase your content for people who are
interested in seeing specifically Unreal Engine
development on Twitch. That's what we do.
You can see the tag down here below if you're watching
this on Twitch. If you're not watching
this on Twitch, you are probably
seeing this on YouTube. If you do, make sure
you hit that notification bell so that you can see
all of the latest updates that come from the
Unreal Engine channel. We not only do
these livestreams, but there are also
plenty of virtual events that are all now
being put on YouTube, the last one being Unreal Build: Virtual Production,
very exciting if you haven't seen that yet. Make sure you follow
us on social media, and next week,
we do not have a stream because we are observing
Thanksgiving here in the US, but the week after, Arran,
what's happening the week after? ARRAN: We're going to be doing
some stuff on accessibility, so all of the cool
engine built-in tools that you can use to make
your game more accessible we're going to be covering
along with some extra theory on how you can kind
of build some content or change your game content so that you can make it more
accessible for more people. VICTOR: And who's going
to present this? ARRAN: It's going to be me. VICTOR: Yeah, damn right it is.
ARRAN: You're stuck with me. VICTOR: Awesome,
and with that, Arran, thank you so much
for coming out today, showing off your procedural
tree generation tool. If you want to know more about
the Procedural Mesh Component, you can go ahead and
go to our documentation. I also believe there are
quite a few community tutorials or tutorials made by
the community around, so you can go to YouTube
and search for some of that. With that said, thanks to
all of you for watching today. I hope you have a
good rest of your week and rest throughout the weekend, and then we will see
you again in 2 weeks. Take care, everyone.