This video demonstrates a comprehensive approach to optimizing Unreal Engine 5 for mobile devices, covering landscape LOD settings to reduce triangle counts, deferred shading with optimized skylight and shadow systems, substrate material fallback to blendable GBuffer for mobile, procedural vegetation LOD overrides, PCG hierarchical generation with runtime spawning, and Metahuman assembly quality settings, all while achieving 60 fps performance on mobile devices.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Optimizing Next-Gen Mobile Features in Unreal Engine | Unreal Fest Chicago 2026
Added:Hello everyone. Welcome to the very last talk of Unreal Engine fest. I am very excited that there is a lot of people here. I lot more than I expected uh because I would expected a lot of go a lot of you to go uh ready for partying right right after this. So thank you for being here. Looks like you're very very serious mobile game developers. [snorts] Uh my name is Arvinda Kanton. I am a solution architect at Epic Games. I look at I I my specialization I would say is a lot of optimization performance and mobile gaming uh in general. Now why mobile gaming? uh for Unreal Engine mobile gaming is very important because it's important for developers because when you look at this stat about 83% of the players who are playing games are playing on mobile and 55% of the total revenue made by games in general is also from mobile and out of that 56% of revenue that's coming from mobile games or midcore games and that's a segment that Unreal Engine is very nicely positioned uh to help developers out into making games and that's why mobile game is is uh is important for all of us. So the agenda of today is very simple. I am not going to show you slides. I am just going to make a live demo of a a game and this is a game I'll be making from scratch. Let me switch to here. Uh if you can see my screen. So, I'm playing this game on my Samsung S23 device, and this has a lot of these features that developers often are working on when they're working on a PC console game, right? It has substrate, it has procedural vegetation uh uh trees. It has uh of course like you know um metahuman and it's using deferred shading and it's also using landscape and and and whatnot. Like there's a lot of these features that are great, looks amazing on PC and console, but can you truly make a cross-platform game if you're going to be uh if you're going to be making this game on a on on a uh or porting this game onto a mobile device also. And that's really what we'll be doing today. We'll make this game from scratch uh on mobile. So, let's get that out of the way.
Let's see if we can do that. Um, oh crap, I didn't really fight. Let me show you the fighting because that's the fun part. Uh, so if I go in there, um, and if I Oh, you can't see it.
Yeah, if I go in here, there's Grus and I will start fighting him. So, it's like a boss fight kind of a thing that I want to be doing. And that's this is the game that we'll be making. And there's a lot to cover, so I'm going to just get right at it. Now, the first things first, when you're making a PC or console game, it's sort of inevitable that you're probably, especially if you're going to be making a uh an open world kind of a game, it's inevitable that you're probably going to be using the landscape system, right?
And landscape. What's Let's create a landscape. So, I'm going to select the selection mode and create a landscape.
And for the sake of >> [snorts] >> u simplicity and to show the apparent benefits that you're going to be getting, I'm going to create a much smaller landscape, just a 7x7 landscape.
Going to click create. And I'm going to do sculpting or anything. I'm just going to leave it as is. Uh let's go to an unlit mode so that we can see what's up.
This is by the way a completely blank screen, blank scene level. It has nothing in it. It's just got one landscape. Now, now what is wrong with this landscape on mobile? Now, if I go down to console and I type in stat landscape like that. If I hit enter, the stat that we are most interested in looking at is this thing called processed triangles.
And it's got it's got like maximum of 722 and it kind of keeps changing like if I zoom in zoom out it even goes to like th00and and we can see it a lot more apparently if I go to wireframe mode and this is what is happening the landscape is loing while I go closer the maximum triangles go up to like even 1,700 and that many pro that many triangles being process processed on mobile is a lot right so how do you then use the landscape but also make it make sure that the same landscape is performant on mobile.
Fortunately for us, if I select the landscape, if I scroll all the way down into my details panel, there is a option here called use scalable LOD settings.
And if I turn that on, I automatically get a couple of options turned on. If I can select that.
Ah, there you go. So now that I that is selected this option here called scalable LOD0 screen size is now available for me. And with that what I can do is I can I can override the LOD0 of the landscape depending on which platform this landscape or this game is going to be deployed into. So if I say like hey on a medium level device if I'm if this is going to be packaged to a medium quality level device then switch it to a uh let's say I'm going to just say five. Now what does this number even mean? What is 0.5? What is five really what does it mean? Let's see it in action first and I'll show you what's happening. Right? So if I switch to my Android preview on let's say a mid-end device it should just switch and now you'll notice that my landscape has gotten a lot simpler and at the same time the number of process triangles have al also gone down significantly right it's gone down from thousands to now like even less than 100 now what is this now what is what did I do what is this scalable LOD zero screen size this means that by default If my landscape is occupying 50% of my screen which is 0.5 in this case then start showing LOD0.
Whereas if on a medium level device if my landscape occupies five times my screen size only then should you be showing LOD0 in which in this case it's an impossibility right because no game is ever going to show five times the screen size. So, which means that you're never ever going to see LOD0 is what you're what you what you what I've done over here. So, this way you can still use the landscape that you're using for your for your PC console game, do your all your sculpting, painting, and all of all of that, but at the same time cap it at a low uh triangle on a mobile platform. Okay. So, now that landscape is done, the next thing that you're going to do is uh you're probably going to be adding lights. So, let me add some lights. Just going to go to window environment light mixer. I'm going to add skylight, directional light, sky, atmosphere, volutric crowd, height, fog, all of it. I can't see anything because I need to be on lit. There you go. So, now I have lights in my scene. The next thing you do right now, what's uh one thing about light?
uh we'll fix this error or this warning that we're getting. But one thing you need to know about Unreal Engine in the recent versions of Unreal Engine is by default the mobile shading is defaulting to if I go under project settings under rendering the mobile shading now defaults to defer shading.
Uh of course forward shading exists.
It's still it's still there but we are going to stick to deferred shading because that's uh for if you're going to be making a open world game with you know outside lighting outdoor lighting dynamic lighting and whatnot deferred shading is preferred of course only modern devices uh support deferred shading but I think modern is a very relative term I think even even my device which is about 5 years old now supports deferred shading so I think we are getting there uh so it's using deferred shading and learn. Let's try to fix this problem. What is this problem? It says sky atmosphere components needs a mesh with a material tagged as a sky normal stuff because uh mobile hardware really struggles with heavy processing required for this kind of realtime full scene atmospheric scattering. So if we instead use a sphere. So I have a normal inverted sphere. So inverse normal going to drop it inside my scene.
and move that to the center. And let me make it like really really big. And now that covers the sky. And it also needs a material that's tagged as is sky. So right. So I already have a material. So if I go all the way down to my materials, I added a a matte sky. Now this is nothing. It's not a very fancy material. It's like a very simple one.
It just has a shading model that's set to unlit.
And it's also marked as a sky like right there. Uh where is it? Uh right there. So it says it's a sky. And so it's an unlit emissive material. Uh a unlit material that's that's connected to the emissive node. That's about it.
So I'm going to select that and use that as my sky material. And that error or the warning is gone. So that's awesome.
All right. Um, one thing I do know is, uh, one thing also you need to do is if I go to skylight, we don't want to be having real-time capture for skylight in your mobile devices because again, real-time capture every frame of your lighting is going to be super expensive. So, we're going to switch that off. Now, you notice the lighting right now, if I switch it off, it becomes kind of flat. Uh, that sucks.
We want to have like good-look lighting.
So instead, I'm going to select the skylight and in my source type I'm going to select a specified cube map and I'm going to use an existing cube map that comes with the engine uh daylight ambient cube map and use that as my skylight source which means I'm still getting good-looking lighting which comes from the sky map from the cube map but it's not being calculated every frame. So we got skylight going on and along with um uh along with uh the the the inverse uh is sky material adding to my skylights. Now um let's actually play the game. Uh I do know that if I this has this sphere has a collision in it.
In fact if I play my character kind of just goes out somewhere. And the reason for that is this inverse normal sphere that I add that I added has a collision to it. So that's why it kind of kicks out my character out of the sphere. So let me just make that sphere without any collision. Uh where is it?
Collision presets. I'm going to set it to no collision. And now if I click on play. Hey, awesome. But it looks crap, right? Because there's no shadows. Why is there no shadows on mobile? It looks It'll look good on a on a PC console.
It'll have shadows. Mobile, no shadows.
Why is that?
If I go under skylight at directional light, if I scroll all the way down, you'll notice by default this has distance field shadows turned on. What is distance field shadows? Distance field shadows first off is super expensive on mobile. What it does is any objects that's that is within this range which is 5 thou 51,200 units. It'll all it'll calculate the shadows of all the meshes within that within that range and then create shadows for all of those meshes.
Um that's too expensive for mobile. So instead of using distance field shadows which I'll turn it off, I'm going to be using cascaded shadow maps. Now, cascaded shadow maps is also turned on on PC and mobile only for objects that is 40,000 units away. Now, what is cascaded shadow maps? Cascaded shadow maps is you have your camera. The camera is divided into multiple layers. In this case, it's it's divided into four layers.
And it's going to then say create higher resolution shadows based on how close the mesh is to the camera. If the mesh if the mesh is closer to the camera, it creates a high resolution shadow. If the mesh is very far off from the camera, it'll create a low resolution shadow.
And if it goes beyond 40,000, then the shadows disappear. Let's see it in action. Right. So, let me not make it 40,000. Let me make it 2,000 so I can start seeing seeing shadows a lot better. So, let me hit play.
It should play in a bit, I hope.
Come on.
Ah, there you go. So, now my character has shadows.
It's running around. Now, let's see.
Let's see the cascading in action, right? Like if I eject out of my game, if I kind of move my camera away, as I move away, the camera the shadow sort of disappears. So, this is super efficient on mobile devices and in fact also on a PC console device.
Uh, and if your shadow looks a little uh if a shadow looks a little off uh on a on your preview like you know it looks a little jittery that's because of your scalability settings. So if I just say like hey for shadows make it look better then this shadow looks a lot better. So this is just on a preview on a mobile device it'll actually look okay.
Okay, so now that we have added the landscape super optimized, we have our lighting very optimized, shadows optimized, what's up next, right? Next one. We have this landscape. We want to be adding material to the landscape.
Now, you can just add your usual landscape material. It's been around for a very long time. But let's say on a PC console game, you really want to do like nanite tessillation using substrate and you want to have like footprints and snow tracks and whatnot. and you want the same game on mobile. How do you go about that? Now, that's a good question.
So, let's create a substrate material and see how it performs and how we can optimize a substrate material to work on mobile.
So, I'm going to go under this folder.
Let's go to material. I'm going to create a brand new material. Uh, I'm just going to call it matt_hago landscape.
Right. And I'm going to open that up.
uh and let's just create a a new material. Now, if you know uh substrate is turned on by default. If you see this front material on your node, uh that means substrate is turned on and and Unreal Engine has substrate turned on by default. So, let's create a very simple substrate material. I'm just going to go into my quantum browser into Fab. I have a couple of uh surfaces textures that I had downloaded from Fab uh from the Quicksell assets. So, let me just get uh I don't know um these three.
It's a mossy surface.
Let me grab that. And as you would with substrate materials, I'm going to create right click and create a slab, a substrate slab. And I'm going to get this albido. Put it to albido. This is a uh a roughness map. So the R uh CRM is uh OM is like occlusion roughness metallic map. So I'm going to get just the roughness and grab it into the roughness and normal map goes under normal map. Pretty simple. And the entire deal with substrate, it it does blending really well, right? Like you can have like a a a material that's on top, material is the bottom. But let's see how it performs on a mobile device.
So I'm going to get a sandy uh texture, which is what I'm going to start blending. Again, this is a very simple material, nothing fancy. Uh, just for the sake of demo is why I just wanted to show everything from scratch.
No pre-made materials. So, create another slab.
And I'm going to grab this diffuse to diffuse, roughness to roughness, normal to normal. So, we have two materials.
And now, let's blend it. So, in to blend it, I'm going to right click. I'm going to create a horizontal blend and I'm going to say like, hey, the mossy material, you could be like your foreground and the sandy would be like my background.
And I'm going to plug this in to my front material.
As soon as I plug this in, a warning popped up. It says substrate material was out of budget and has been simplified. Now, why is that?
If you are going to have first off, if you go if I go under project not plugins if I go under project settings uh if I search for blendable Gbuffer blendable GBuffer this one says like hey substrate Gbuffer format is blendable Gbuffer. The other option that you have is something called adaptable Gbuffer. What does this mean?
This means that even if you have adop adaptable Gbuffer is what makes substrate amazing, right? like you can have like layered materials. It looks you can have like clear coats and all of those nanite tessellation and all of that. That'll only happen if you have adaptable Gbuffer. But if you have the same material ported to a mobile or even a DirectX11 device on PC console, then it will immediately fall back to a blendable GBuffer. And that means that it's going to behave like your legacy materials. It just takes all the both the slabs and batches it as one batch and sends it to the renderer as opposed to what adaptable Jbuffer does. It still does a pretty a pretty approximate job, but let's see it in action, right? Like so if I have this going on, uh it the horizontal blend also requires some kind of how much mixing or how much blending needs to happen. So, let me just say like, you know, create a constant. And I'll just say like, you know, the grass material needs to be 50%, and the sand material needs to be 50%.
And click apply. And that should save.
And uh yeah, let me go back here. And I'll just say like, hey, use that material uh for my landscape. Uh select my landscape and use this as my material for my landscape. So, there you go. So I have a 50% moss. Let me remove the grid.
I have 50% moss and a 50% sand blended by substrate for a mobile device. And you can see it like you know it works all right. Like even if I change this to like I don't know 10% um sand or 10% moss and 90% sand. Then that applies and I can go back to my material and now I have like full sand going on as opposed to the mix that was that that you were noticing earlier.
>> [snorts] >> Now, the real power of using a landscape material is you should be able to paint on it, right? You don't want to just have like a mix of two materials. You want to be able to paint the landscape to have like different sorts of uh sorts of stuff uh sorts of uh weightage. Now, in a traditional landscape, if you've been creating, you would have created what is called a landscape blend.
Landscape layer blend, right? Everyone uses that. Unfortunately, landscape layer blend does not work on substrate for obvious reasons because you're using the horizontal blend and vertical blend.
So, landscape layer blend does not work.
So, then how do you then paint on a substrate material? The answer for that is you instead use what is called landscape layer weight node. Let me just call this layer weight called mossy layer.
And this allows you to add weights on different parts of the landscape. So this mix value essentially becomes a weight value that we're going to be adding based on the landscape component.
Let's see it in action. Right? So, uh, in here I'm going to just say like, hey, uh, create a vector 3, which is just my color. And let's just make it like, I don't know, sort of grayish color because gray is 10% of grass, 90% of moss or something like that. So, I'm going to plug that into my layer. And into my base, I'm going to say that my base color is going to be zero.
And I'll plug that into the mix. And I don't want this anymore.
Now, what's happening here? Let's see it in action. So, uh, apply.
Apply.
Come on. Save.
And let's go to, uh, landscape and start painting. Of course, I can't paint in Android preview. So, let me switch preview.
And so, here I am going to select my paint tab and scroll all the way down. And I'm going to start adding layers to my landscape. So I'm going to use this this little button that is not a lot of people know about. It automatically creates layers based on whatever layers that you have created in the landscape.
So I'm going to select the mossy layer.
That's the name of that. That's the name we gave, right? Mossy layer. And uh create a new layer info.
Standard stuff. Usual stuff that you do in in landscape painting. And let's just reduce this brush size. And remember the game I originally showed you that had an arena, right? It had like a a round arena. So, let's paint that arena. So, I'm going to select that mossy layer.
I'm going to start painting it.
And you'll notice like it's doing this blend of like grass and sand together.
It's not entirely grass at all because our color that we chose in the in in here is like a 46%.
Um like you can see it's like 46% is what the the blend is. So if you change that to entirely white then it'll be like fully green. Um so let's in fact let's see it in action too. Let's see that. So if I say okay.
Yeah that's done. So if I go back to selection, let's in fact see that like let's change it to like maybe more white. Click okay. If I apply go back then you'll notice it's become more green. Right? Uh and that's how you're able to paint this. Now let's see something quite disappointing. Now uh you have this you have painted a landscape using substrate. Now, if I switch to Android or if you deploy this to an Android device, bam, that landscape layer weight is gone.
Now, why is that? That's because the landscape layer weight uses a very specific weight map data per landscape component and it calculates that as opposed to on a PC console, as opposed to on an Android device, it requires a baked version of the same thing.
So if I have a very beautiful landscape that I have painted here, uh let me fill that in too. Uh but if I if I want the exact one exact paint exact painting that I done to also be baked as a texture and then sent to Android.
How do you do that? Let me show that to you. For that, what I'm going to do is I'm going to select my landscape.
Uh let's switch that back. And in here under manage there is an option here called import.
And this is very counterintuitive. If I select the import option I have an option here to export under import. Right. So if I select export I can select the mossy layer that I had painted and export this as a PNG file. So I can go into my boss file and I can just say hey mossy layer baked.
So what this does is this has essentially exported a oh I haven't exported I have to click on export that helps. Uh this has exported a baked version of the painting that I had done. It's exactly that. Now, this is super tiny.
It's like only 57 x 57 pixels. Now, you can go to an image uh processor like Photoshop and then upress it. But for the sake of time, I'm just going to use this low res version of this. And let's see what happens because of that, too.
So, I'm going to go into my material and I'm going to say like, hey, uh this is this is fine on a PC console, right? But we only want this to want this to be the case in um uh on a on a mobile device.
So I'm going to use this node called feature level switch.
And this is a node that's been around since for a very long time. We use it in Fortnite quite often. And I'm going to say use this layer landscape layer weight on a SM5 and an SM6 device.
But on a default, which is my mobile device for example, I am instead going to be using this uh this texture instead. So, let me just get that import that texture real quick uh multi layer.
And I'm going to drag that in and I'm going to say like, hey, use this instead for my mix.
Click apply. If I go back, if I switch to an Android preview, it looks, this is what it looks like.
Why is that? Because it's a very, very tiny texture. So, we It's like super tiled. So, let's fix that too real quick. So, I'm going to start tiling it.
So, for tiling, I use this pretty neat trick. I use a texture coordinate.
Uh, and I'm going to have a constant.
And I'll multiply this multiply this with this. And I'll just make this like 0.1 and and have a reroute function reroute node. And I'll call this landscape scale.
So this is a reroute function. It's pretty nifty. So, if we call this styling um and this what this does is I can then say like, hey, um what what did I call it again? Landscape landscape scale. So, I can then say like, hey, landscape scale for all my textures. I'm just going to plug this in. Just scale it up to that whatever I have. So, it's a So, I can do the same thing for here too. Landscape scale.
Plug that in. Plug that in. Plug that in. And also do the same thing for our texture here. So, landscape scale.
Uh, I know it's going to be super tiny.
So, this is like a sorry, a hack really um point. Ideally, you would want to just do this using a image processor.
So, I'm going to multiply this, multiply this, plug that in. Uh so this is our mobile override and this is our SM5 and SM6 override.
Yeah. Select that.
Move that out of the way. Yeah. So we have all of that. So now let's apply.
Let's go back into the material.
Um come on. Apply. Save. And so now I have the same material baked on PC console. It looks like this.
On a mobile it looks exactly the same, right? Slightly tiny. Maybe I need to work on the multiplier a bit, but you get the idea. So we have a substrate landscape material that is working exactly as you want on a PC console. And now there's a workaround where you can also use landscape layers and painting that you can also then put it on a mobile device. Good. All right. Now that we have the landscape with the materials on on top of it, now the next thing we want to be doing is adding uh some foliage on top on on this one. Right. I have like 20 minutes more. Uh so there's a lot to cover now. All right. So what is the what is the foliage?
Uh the foliage that has been often talked about is the procedural vegetation editor. And everyone is like hey use that. It's awesome because it's got like nanite nanite foliage uh and it's uh it it creates this beautiful looking trees and whatnot. So this is a tree that I have looks great and I essentially just exported it. So exported it and but when I exported it I had two options which I wanted to show you why and how it looks like on mobile. Right? [snorts] What I did was in here I said like hey export this as a static mesh create an an foliage. You're seeing the warning of nanide foliage not being there because I'm on I'm on Android preview but if you turn it off then this will go away. And it's also has like two options which says do you want to preserve uh sorry do you want to preserve the nanite shape which is none or do you want to use waxilization. Now the the middle option called preserve area is a legacy one. So we're not going to use that. So when you say none versus voxalizing your shape, how does this affect mobile game development?
When you export it as a voxalized mesh.
So here you can see it's like PVE voxalized and I'm on Android preview. If I open that up, this is what voxalized trees look like. If you like that, sure, go ahead with it. Right? It's a pretty I would say stylized version of the tree.
Um I don't like it. But if you don't want to preserve the area as a voxil, then this is what the tree looks like.
Um like I said, like you know, this is the tree itself. So if you if you export or if you have this tree on a PC console, this is what it'll look like.
But on a mobile device, it's uh it's automatically kind of torn down. Uh you'll notice that on the nanite triangles it's about 59 or how many ever? That's a lot of triangles. Whereas on a fallback triangle it's only like 3,420 triangles. And that's what you're seeing over here.
And so you can still use PVE but it's going to look a lot reduced automatically on a mobile device. In fact, this is a tip not just for uh PVE or procedial vegetation editor. This is a tip in general for any static mesh is if you feel that the number of triangles that you're seeing like the fallback triangles or any triangles for that matter on a mobile device is a lot, you can further go into uh into the LOD settings right here and you can autogenerate more LODs for your particular static mesh. So let's say I'm going to say like, hey, create three more LODs so that it kind of does this LOD. So I'm going to click apply changes. That usually takes like less than a few seconds. And once it does that, I can then add an override of this particular mesh. Like now it's done. So I have like three LODs. I can say there's LOD0 which has about this uh oh it has uh this many triangles and then LOD 1 has lesser number of triangles and LOD 2 has a lot less number of triangles and you can see the visual quality also changes right so LOD 1 LOD 2 LOD 3 now if say on a mobile device you're you're you're you know you're putting it on a very low end device for example you can then say like hey on the minimum LOD let's override it similar to a landscape that we're doing earlier. So, minimum LOD, I'm going to click on plus and I'm going to say on a mobile device, don't even bother with LOD0.
Instead, just use LOD 2 or whatever other LOD that you're going to be using.
So, when you're and click on apply uh that's that's down. So, what this does is even when your game is being packaged, it'll ignore LOD0 and LOD 1 and instead only package LOD 2 or anything lesser than that. Uh so your game also becomes very light in terms of like the package size and you're also not adding computationally expensive meshes in there. Okay. So now that we have this mesh going on, um let's now populate this our our our uh our arena with this mesh. I also by the way have a grass that I stole from a very optimized grass uh that I stole from the soul cave fab place fab marketplace which is by Unreal Engine uh if that shows up in a bit. So I got that grass uh which is optimized for mobile and I'm also using this PVE uh tree that I've used. So that's the grass. It's pretty optimized. So let's add the grass and the tree to this uh to this arena.
How do I do it? I want to use PCG.
Let's create PCG. So, I'm going to right click, scroll to procedural. I'm going to create a PCG graph. Going to create an empty graph. Call it PCG Chicago environment.
Let's open that up. Okay. And you know, PCG graph normal stuff. Again, I could have done this previously, but I want to do everything from scratch. So, I'm going to do the same thing that we do earlier. I'm just going to get the landscape data.
Uh I'm going to get a surface sampler of the landscape and I'm going to then transform the points. Let's see it in action actually. Um so I let me just drag let me just drag this PCG into my environment.
Right. And I got this PCG graph in here.
Uh if I click on my D button, that'll debug it. So I have my points and let me just in the transform points, let me just do some offset. Um I don't know um like you know rotate it randomly from 0 to 360° which got rotated and also scale it up by 7 minimum and I don't know 1.5 maximum. So you got like this random grass action going on.
Again, typically if you're going to be using your traditional landscape, you could have just used the landscape grass, but I think this is a lot more performant because uh I'll show you why.
So, I got the transform point and I'll also create a static mesh spawner. And the static mesh that I want to spawn is my grass. So, I'm just going to select my grass.
All right. So, let's see what that looks like. If I go to the side, I'll remove my debug points. And that's my tiny tiny grass.
It's too low. Maybe I will change the surface sampler to be sampling a lot more points. So, let me make it a lot.
Yeah, that's more like it. Lot of grass that I have.
Is this efficient? It's not at all efficient at this point of time. Uh let's see. Let's make it efficient. Uh while I'm making it efficient, let's also create a surface sampler to add my trees because we created these beautiful trees. Let's also add those trees. So, I'm going to do the same thing. I'm going to transform points uh points.
And in here, now we have painted the landscape, right? Let's really make use of that landscape. So, I'm going to also uh get my Yeah, I've got to change the rotation, scale it up uh a bit.
scale it down a bit, whatnot. Um, standard stuff. But I'm also use going to use a filter attribute or attribute filter I should say. And this allows me to then sample the landscape. So if I hit A, that'll show me all the attributes on my particular landscape.
Oh, not this one. Yeah, here. And you'll notice that if I scroll all the way to the right, our nice little mossy layer shows up here, which we painted earlier, right? So, we can actually use this to add our trees not inside the arena, but outside the arena in the sandy area. So, let's use that. I'm going to remove the attribute and I'm going to say like hey in the in the filter attribute uh anytime the mossy layer mossy layer case sensitive is moslayer what what comes not lat man terrible at typing moslayer is equal to has a threshold.
We'll use a constant threshold. So constant threshold of zero only. Then spawn a static mesh. Spawn static mesh.
And we will use our mesh entries as the trees that we just created.
Uh what's where's our tree? Let's use the notw walk one because that's what we want. Use that as a static spawner.
That's what that looks like. Yeah, there you go. So we have the trees around the arena not inside the arena but around the arena. So we have in fact for mobile and so your your workflow essentially remains exactly the same as earlier except that you know you are still working on mobile. Now is this optimized? It's not at all optimized.
It's terrible. It's it's like you know if you it'll have like a it'll just like crush your frame rate on if you deploy this. So how do you then optimize this grass on a mobile device?
A few things. First, one thing I want to I want to mention is it is sort of optimized. PCG is sort of optimized automatically because where is my PCG? Any static mesh that you're going to be spawning is automatically an instance static mesh component. And what that means is even if you have if you have the same mesh multiplied or you duplicated multiple times inside your level, it's going to batch all of those draw calls into one, which means it's pretty optimized on that front. But if you have like a large landscape with lot of grass and a lot of trees, then this method will will not perform really well. So let's make it work well. First things first, I'm going to go under my graph settings. It's my PCG graph settings. And I'm going to say like, hey, uh, use hierarchical generation.
And if I turn that on, what that means is going to say like, don't generate everything all at once. Instead, only generate this if if you're within if your tile limits on your grass is this big. Let's see it in action, right? Like I said, let me make it something aggressive like I don't know 800 like really small and nothing happens because we also need to go to the PCG volume itself and make a couple of changes in my details panel. The first things I want to do is I want to say don't generate this grass on load because it's a open world system. I'm going to generate this on runtime so that disappears.
I also want to make sure that this grass is part this is this PCG is uh partitioned and that's how it's part it's going to partition the landscape into 800 by 800 grid which is what we set up in here as 800 in our hierarchical generation.
And it's going to change all of this grid. It's going to divide the landscape into 800 by 800 grids and only then will it actually start generating the grass.
Now, because I have said generate on runtime, that's why the grass disappeared in the editor. So, let's actually fix that too. So, what I'm going to do is going to select the PCG world actor and I'm going to say, hey, treat the editor as a viewport generation source. If I turn that on, a grass shows up. Great. So now you'll notice that the grass does not generate through my entirety of the landscape but in fact only generates on a 800 by 800 grid. See that?
So that is optimized in one way but I don't like the way in which the grass or the trees are kind of popping in and out. That looks kind of terrible. So let's fix that. And it's also like you'll notice that the grass in fact is always popping in as a grid. And in a game like say playing Fortnite, you don't want to have like grid kind of popping off your of your grass, right?
So let's fix that too. Uh right now 800 is too aggressive, right? Let's actually make it I don't know by 3,200 units for grid size. And in my static mesh spawner of the grass, I have this option here called instance end distance call sorry instance end call distance what that does is if I say let's make it to about 2,00 it's going to automatically you'll notice the grass right now it is not appearing in grids but instead appearing as a circle and if I hit play actually the grass will disappear if I play and the reason for That is because I also need to make sure that the serialization mode is always serialized. Okay. Now, if I click play, you'll notice that now the grass is kind of like appearing in the cull distance. Now, if you want to make the call distance a lot longer, you absolutely can. But now the the grass is also only generated based on the 3200 size grid. And it's also getting culled in a distance. So it's like double uh double kind of a a uh optimization that we have done over here. And because I had set that uh the hierarchal generation to be over 3,200 the the the grasses are called but the trees around me is not getting called and that's by design because I don't want the I don't want the trees to pop in and out. I only want the grass to pop in and out. And so that's pretty good. Okay. So now that we have this going on, um, if you don't want if you want to add a PCG element to your scene, which is not tied to any of this, it's going to be like, let's say a static, like, you know, in our case, if you remember the game, it had like a wall uh around the arena. And that wall, you don't care about it on a static mesh. You can create a new static mesh like that's what I'm going to do or or a PCG graph. So, I'm going to select uh the new PCG mode that exists and I'm going to start drawing a spline by selecting this landscape. And I'm going to say like, hey, just draw a spline, which is going to be my arena.
And I'm going to say like, hey, use a count of 10. It's super easy. This essentially creates another static uh mesh spawner through a PCG element. So I'm going to click plus+ two two walls which I already have from my quick mega scans. So I'm going to select the static mesh one and static mesh two.
Um it's kind of rotated oddly. It's rotated the other way. So let's fix that too. So let's fix the global rotation to be about 180. There you go. So click on accept. So now I have two PCG graphs.
One is not curled, not optimized. Uh it's just going to be there all the time. And the other one is my nicely curled, nicely optimized PCGS PCG. So you have both. Okay. So now that we have an arena, we have grass optimized, we have shadows that's optimized, we have landscape that's optimized, the last thing we want to do is metahumans as our main character. So let's add a metahuman. So I metahuman usually takes a little bit of time to process and whatnot. So I created a metahuman up front just so that we can save some time. So if I go under metahuman, this is a metahuman I created called MTH Chicago Mikuel.
Um, now when you're creating a metahuman, I just use a preset. Uh, you create a joint, you create, you download the textures, all of that happens. The important thing to have a metahuman that's optimized for mobile is when you click on assembly, there's an option here called UEI complete. But you have other options here called UI complete, UI optimized, UF, and export. What we care about is UE optimized. And in here you can then say how what is the quality of the of the metahuman that you want to be exporting.
I'm going to say a medium. That's what I selected. And what that does is essentially high means that the textures that's going to be associated with the metahuman is going to be like a 2k texture. If I select a medium then it's going to be 1k texture. If I say low then it's going to be like a 512 x 512 texture. And you can of course override it if you want. Uh but that's what that that's essentially what this does. I exported a medium metahuman. And when you export a medium metahuman, it creates a really cool blueprint.
And this is what the blueprint looks like. You have a metahuman with the body, with the face, with the beard and mustache and all of that already assembled for you. Now you can take this exact blueprint and you can then add go to your event graph and then you can start adding your uh your your gameplay elements to it. But if you're like me, if you're like, you know, I just want to port this metahuman to a third person controller or third person character that already exists, here is like a workar around. I wouldn't this like kind of works. How would you do it? So um let me just go to my third person blueprint and I have the third person character.
The usual third person character person Uh, let me just duplicate this guy so that we don't touch him. And we'll say, hey, BP MH Chicago. [snorts] You'll notice that I've practiced a lot of times. That's why you have the duplicates over there. But you have the Chicago MH Chicago player. This is what we'll be using. So, we will first say, hey, I don't really care about this mesh. We want to be using the metahuman mesh instead. Right? So, I'm going to say like, yeah, just go away. Go away, Quinn. Go away. That goes away. So, let's go back to our metahuman blueprint.
This goes away. Metahuman blueprint. I'm going to copy the body, face, beard, skeletal mesh, all together. Ctrl + C.
And I'm going to Ctrl V it into my uh into into here. Oh. Oh, did I Yeah, wait. Did I control C correctly?
Ctrl C copy.
Okay. Uh it looks strange. It should have it should have in fact gotten the the name of the mesh also. I don't know why it kind of did not do that. It typically should do that. All right, that's fine. Um, so make sure that the uh that the hierarchy remains the same because you'll notice that this is in fact the face. This is in fact the body and also get all the groom and put that in the skeletal mesh. Oh, we are almost out of time. I have like five more minutes and we should be done very quickly. Sorry about that. I know you're all want wanting to party. Um, okay. And then we'll position it correctly.
And because we're running out of time, um, let me just do a quick work around.
So, now that I have this, um, if I go to my, uh, world settings, and if I select, uh, instead of the game mode override, I'm going to select our Chicago character.
And that's going to be my meta my player right now.
And I should not have clicked save.
Okay. Anyway, so now that's my metahuman kind of not doing anything. He's kind of like running around like that. But as the fix is simple. Uh it's all you need to do is if I'm selecting the metahuman, right? If I go to my blueprint of the meta of this character, this character, all I had to do was I got the uh the the uh the anim animation blueprint of my of my third person character and I which is right here. I got the the animation class. I rightcicked it and I retargeted the animation and then I retargeted that to my metahuman character. And then with that all done, that's all I needed to do. I retargeted it and then I put that as my as the charact as the main character or the animation class of this new blueprint that I just created. If I click on play, nothing happened because I need to go here and select this character. So now if I click on play, I have our metahuman character running exactly like our third person character. And that's awesome.
And finally, because we ran out of time, the only thing I really didn't you really need to do now is if you have like combat variant, for example, the only thing you really need to do do now is um add a enemy AI, which is what I did. I added a BP enemy AI, which is this GR that we have. And I also added a nav mesh which is what I have somewhere uh as a nav mesh. And in fact this is the path that it has created. And uh that's the path of the nav mesh. And now I I have a fully playable metahuman versus uh metahuman versus paragon gro. And by the way this guy is also a metahuman. And uh you must have noticed that we released something called metahuman crowds that is super optimized on mobile and all of that works really really well on a mobile device. In fact, if you don't believe me, this is my performance metrics that I just took on this exact game. I didn't do anything. I didn't do any more optimization than I than what I just did right now. It's in fact a dev build, not a shipping build. And it's running at uh 60 frames per second. Uh you'll notice that this red is because it's actually not bad. It's 16.7 milliseconds, 51% of the time. Uh but otherwise it runs 60 frames per second. Uh everything else looks green. You'll notice that there is a texture streaming problem because I didn't do any device profiling or device profile caps on on on textures which you do then you're good. Uh then you get a really really good looking good running game. Okay. Uh that's about it. Uh I just want to leave with few more slides.
last few slides. So, first off, uh if you want to know more about performance tuning and testing and whatnot, I gave a talk at GDC this year. Uh so, check it out. Um and that'll go into details on how further you can go about optimizing your mobile game. Um right, and then there's a lot of QR codes. Second, uh if you want to know more about like you know adding mega lights into your scene and whatnot into your mobile application, our friends at ARM did a an amazing project called neural dawn uh with which you're able to uh you know use Unreal Engine to uh to have like mobile enabled megalytes. So uh it's done by ARM uh we didn't do it uh and they op they created a branch of Unreal editor to get it done. Similarly, if you want to know know more about deploying to Qualcomm devices, uh then check out the Snapdragon game toolkit uh which is what is over there. And finally, uh Louisaldi and I uh we worked on a mobile learning path. So, if you're just getting started with mobile game development, uh this is a really really nice collection of all the links that you'd ever need for mobile game development. So, uh check it out. It's it's awesome. And finally, everything I just talked about is documented on a EDC post that I just created. Um, so if you want to follow along and redo this exact project on your own on your own machine, uh, just follow that QR code and you should be able to like recreate this boss fight exactly the same way I did. So with that, uh, thank you so much. Uh, I know we are like about 5 minutes over time or little over 10 minutes over time. Damn.
Uh, sorry about that. But now it's time to party. I don't know if you have time for questions, but I'll be around. Uh, I'll be at the party also. So, if you have more questions, uh, do do let me know. But with that, thank you so much.
Hope you had a great fest and awesome.
[applause]
Related Videos

Audi RS5 4.2 Tuning JDEngineering
JDEngineering
1K views•2013-11-14

DALI + KNX: 500 Lights Offline! BCU Code Lock & Short Address Fix!
EngineerIsmailTech
560 views•2026-04-13

Explaining Quality Control of Concrete
maherbader
4K views•2019-05-25

World Mining Production Peaks - Lead Antimony Arsenic Titanium & more
LucarioandDialga
1K views•2019-04-19

Tech Titans: LFP vs Sodium-Ion Battery | Which is the most effective energy storage solution?
Enfsolar
522 views•2025-11-06

Doing the Math: Analysis of Forces in a Truss Bridge
TeachEngineering
1K views•2025-06-06

Inside Midnight Fighter Jet Refuelling Secrets of Stealth Missions | WION Podcast
WION
3K views•2025-09-20

Flash Point, Fire Point & Auto Ignition Temperature
HSELessons
38K views•2019-08-28
Trending

One Must Imagine Sisyphus Happy
vlogbrothers
61K views•2026-07-21

Future of Taylor Farms
maighstirtarot5385
11K views•2026-07-21

The Downfall of OnePlus!
techwiser
65K views•2026-07-21

My Friend Locked Up The Engine On His K-Swapped Bug...
boostedboiz
128K views•2026-07-21