EpicGamesExt / BlenderTools

Blender addons that improve the game development workflow between Blender and Unreal.
https://epicgamesext.github.io/BlenderTools/
MIT License
2.77k stars 52 forks source link

Send to Unreal - How do you best export complex objects - Question #195

Closed ItsCubeTime closed 3 years ago

ItsCubeTime commented 3 years ago

image

Hi, I have several objects with several basic materials (no textures, they're all using principled BSDF with me just changing the input parameters directly on the node) together making up a corridor. My scene includes several "assets", one of them being this corridor.

In this case I've parented everything thats supposed to be visible to a single face object which Ive added a array modifier to (in order to stack several objects in my corridor with just 1 array modifier) using mesh instancing in the obj properties panel.

Just for the sake of testing I tried putting this face object in the mesh collection alone and to my own surprise all the objects parented it actually exported to Unreal. But each instance of each object now imported as a separate mesh (So I have like 40 copies of the same mesh in my untitled_asset folder currently lol).

Now I couldnt really find any tutorial explaining how one would import several objects like this. What I would like to achieve is a way for me to not have to place each imported mesh individually in the Unreal Editor, but rather be able to drag in all the meshes at once. Im also curious if Unreal can automatically make sure that identical objects get instanced? (For the panels on the wall Im using several objects with linked geometry, can Unreal Engine/Send to Unreal detect this?).

Would appreciate if someone could take a look at my file and show me how you would go about it 👍

Im also wondering if I can automatically merge all my different materials into just 1 material per object or 1 material for all objects for the sake of reducing drawcalls.

Link to the .blend file: https://u.teknik.io/JkOHx.blend

Also do you guys know if there are any other tools that you could use in co-junction with Send to Unreal for (relatively automated) mesh optimization? Ive been thinking of writing my own .py addon for this myself for a while (The idea on solution for this that Ive had is to to generate LODs and such automatically using the decimate modifier since its quite superior to Unreals LOD generation tools and automatically removing faces that wont be visible anyway with help of union booleans - and basically packing this into a 1 click solution kinda deal).

Cheers from Sweden :) Glad to see Blender support by Unreal

ItsCubeTime commented 3 years ago

Also curious on the lights, can I make it so lights are automatically added to the Unreal Engine level along with the mesh?

And about materials, about how complex materials can the exporter actually export properly (what are the limitations)?

ItsCubeTime commented 3 years ago

Also I should probably mention, the end result in Unreal that Im going for is an as close as possible replication of the corridor you see in my blend scene. Its going to be for a simple ping pong game. So since its rather long it would be nice if I could get mesh instancing to work - Also for those panels mentioned.

Feel free to dig around in the .blend file. Any advice/tips are appreciated

ItsCubeTime commented 3 years ago

And how would I export hand-made collisions along with my meshes?

james-baber commented 3 years ago

@ItsCubeTime Send to Unreal is basically a one step fbx export/import tool. So basically it is limited by fbx and what python calls are currently possible in the Unreal python API. To answer your question, Send to Unreal will not setup the instancing for you, that is something you will manually have to do. Also materials are going to be just basically your color and normal that get transferred.

However, Send to Unreal will not overwrite the Uasset data in your unreal project. So how I would recommend doing this scene is using Send to Unreal to send over your assets initially, then setting up the instancing in unreal, and the node setup for the materials how you want them. Then you can tweak/edit the meshes and keep sending over the assets and see how they look in Unreal. Send to Unreal will overite the FBX import data but not your uasset data i.e. unreal materials, instancing, etc.

Currently each object exports separately, but this feature will let static meshes children be combined into one mesh if this option is on. (currently working on this, probably will be done today if nothing else pulls me away from it.) https://github.com/EpicGames/BlenderTools/issues/70

Here is how you do custom collisions. bottom of this page

ItsCubeTime commented 3 years ago

Hi James, thanks for your reply 😃

Send to Unreal is basically a one step fbx export/import tool. ... However, Send to Unreal will not overwrite the Uasset data in your unreal project

I see, why did you choose particularly fbx? Im not an expert at file formats but doesn't collada preserve more data? I know that Godots blender plugin uses a modified version of this file format.

At a first glance it seems like Collada would be capable of most things: https://www.khronos.org/collada/ . In contex of shaders maybe one could extract HLSL code from shaders made in Blender and use those in a uasset?

Currently each object exports separately, but this feature will let static meshes children be combined into one mesh if this option is on. (currently working on this, probably will be done today if nothing else pulls me away from it.)

70

When you say combined into one mesh, do you mean literally joining the geometry into 1 object?

To give an alternative solution, maybe make a custom C++ class instead that acts as the "parent" object. This class could then also include functionality to ensure several meshes are never sent to the graphics driver twice and instead use instancing (If that is not entirely out of scope for this project).

Send to Unreal will overwrite the FBX import data but not your uasset data i.e. unreal materials, instancing, etc.

Particularly about exporting materials, is there anything I could do to help out with as a contributor to allow for some basic materials to be able to be transferred from Blender to Unreal? I have some prior knowledge about working with both C++ and py.

james-baber commented 3 years ago

@ItsCubeTime yea there are several "better" alternatives to get assets out of blender, but fbx is really the only option for getting meshes with bones into engine at this point in time. We are not married to FBX, so if there are better file formats that come along and have python exposure in Unreal then we will shift towards better alternatives.

Yes so currently this feature would apply all modifiers, then join and export the mesh while preserving the original modifiers and hierarchy.

To give an alternative solution, maybe make a custom C++ class instead that acts as the "parent" object. This class could then also include functionality to ensure several meshes are never sent to the graphics driver twice and instead use instancing (If that is not entirely out of scope for this project).

I have not looked into this, but it would be very nice to have. The main obstacles is getting everything to work using just python. The team I work on can put pressure on the engine team to expose some python features in upcoming engine releases, but the turn around is not fast, and is not their first priority. Also we decided that we are not going to ship a separate plugin for unreal to include the needed c++ uclasses and ufunctions needed to make the python bindings. So keep that in mind... the stuff we have to work with on engine side is whatever is currently listed here: https://docs.unrealengine.com/en-US/PythonAPI/index.html

Python is being passed remotely via sockets to unreal here if you want to look https://github.com/EpicGames/BlenderTools/blob/master/send2ue/addon/functions/unreal.py

Particularly about exporting materials, is there anything I could do to help out with as a contributor to allow for some basic materials to be able to be transferred from Blender to Unreal? I have some prior knowledge about working with both C++ and py.

Yes if this is something you would like to work on we welcome PRs. You could open a feature issue for this and layout what would need to be done, like the blender material node to unreal node mappings, and then the python calls needed to instantiate and link the nodes on the unreal side.

drichardson commented 3 years ago

To give an alternative solution, maybe make a custom C++ class instead that acts as the "parent" object. This class could then also include functionality to ensure several meshes are never sent to the graphics driver twice and instead use instancing (If that is not entirely out of scope for this project).

I have not looked into this, but it would be very nice to have. The main obstacles is getting everything to work using just python. The team I work on can put pressure on the engine team to expose some python features in upcoming engine releases, but the turn around is not fast, and is not their first priority. Also we decided that we are not going to ship a separate plugin for unreal to include the needed c++ uclasses and ufunctions needed to make the python bindings. So keep that in mind... the stuff we have to work with on engine side is whatever is currently listed here: https://docs.unrealengine.com/en-US/PythonAPI/index.html

Some half baked ideas to think about:

Blender objects can share mesh objects (Duplicate Linked to see this in action). Perhaps a single static mesh uasset could be exported in this case, 1 for each blender mesh, instead of 1 for each blender object. The arrangement of all the blender objects referencing the same mesh data could be sent to UE4 as a blueprint made up of either: a) an instanced static mesh component with the transforms set to the positions of the blender objects or b) N static mesh components with transforms set to position of blender objects.

For option (a), your blueprint could be a blueprint component (since it's just 1 component), but for option (b) it'd have to be a blueprint actor (since it's a collection of components).

As far as I understand, the Blender FBX exporter doesn't know about linked data (aka shared mesh data), so to make this work with, you'd probably have to select one of the Blender objects containing the shared mesh data to be the one that is sent over, and then do the rest of the work in python to construct the blueprint asset.

ItsCubeTime commented 3 years ago

Hi I'm on my phone right now, but instancing with blueprint classes doesn't work in UE at the time being (not even the automatic runtime instancing added in ue 4.2 something). And the Hierarchial static mesh component wouldn't allow for instancing between objects of the class.

So from a performance perspective I'm not so sure using Blueprint classes would be a good route unless there are some fixes for this done to them

drichardson commented 3 years ago

instancing with blueprint classes doesn't work in UE at the time being (not even the automatic runtime instancing added in ue 4.2 something).

This statement is incorrect. You can have a blueprint actor with a UInstancedStaticMeshComponent.

Just for the sake of testing I tried putting this face object in the mesh collection alone and to my own surprise all the objects parented it actually exported to Unreal. But each instance of each object now imported as a separate mesh (So I have like 40 copies of the same mesh in my untitled_asset folder currently lol).

If your goal is to combine the meshes so you don't have 40 copies of the same mesh lying around, you can try the Combine child meshes feature James added in #196. The downside is you're going to be using a lot more data if the mesh is just a bunch of copies of the same underlying mesh. This is why I suggested generating a blueprint as an option, because you can have 1 Static Mesh that is used by a blueprint actor with 40 UStaticMeshComponents (each of which can be individually culled by the occlusion culling system) or a blueprint actor with a single UInstancedStaticMeshComponent that has 40 transforms in it.

ItsCubeTime commented 3 years ago

This statement is incorrect. You can have a blueprint actor with a UInstancedStaticMeshComponent.

Yes it is very correct (unless they did a patch for this recently).

Idk if there is any official statements by Epic on this but if my word isnt enough, read Kalle_H first post here: https://forums.unrealengine.com/development-discussion/rendering/1657862-4-22-auto-instancing-question . "Blueprints sometimes don't get this autoinstancing and that is a bug. Not sure is it reported yet."

And if you were to read my whole post just a sentance later

And the Hierarchial static mesh component wouldn't allow for instancing between objects of the class.

If someone is to implement a more complex system for dealing with multi object assets than #196 you might as well go all the way. Yes per blueprint class you can use either the hierarchial static mesh component or the regular static mesh component but this wont work across blueprints - and this would become an issue once you start doing kit bashing with these blueprints (re-using the same blueprint many times in your level).

Tho from a memory management perspective just for hard drive space I guess it doesn't really matter.

drichardson commented 3 years ago

This statement is incorrect. You can have a blueprint actor with a UInstancedStaticMeshComponent.

Yes it is very correct (unless they did a patch for this recently).

Here's an example of UInstancedStaticMeshComponent working in a blueprint class. Open InstancedTest2 level to see it in action.

https://github.com/drichardson/UE4Examples/tree/master/Instanced

Auto-instancing refers to UE4 trying to turn normal UStaticMeshComponents into instanced objects to reduce draw calls without you having to do it yourself using UInstancedStaticMeshComponent. UInstancedStaticMeshComponent works just fine.

Additionally, if you need multple meshes instanced in a single blueprint, you can have multiple UInstancedStaticMeshComponent (or it's hierarchical sub-class), each with a different mesh they are instancing. Here are some screenshots from BP_ActorWithInstancedStaticMesh from the example I mentioned.

image

image

image

image

Hunanbean commented 3 years ago

@ItsCubeTime Due to the scope of this particular project, maybe this is more what you are looking for https://github.com/xavier150/Blender-For-UnrealEngine-Addons

ItsCubeTime commented 3 years ago

@ItsCubeTime Due to the scope of this particular project, maybe this is more what you are looking for https://github.com/xavier150/Blender-For-UnrealEngine-Addons

I dont think it supports automatic imports in Unreal however :l Nor does it attempt to solve importing shaders to any extent.

ItsCubeTime commented 3 years ago

This statement is incorrect. You can have a blueprint actor with a UInstancedStaticMeshComponent.

Yes it is very correct (unless they did a patch for this recently).

Here's an example of UInstancedStaticMeshComponent working in a blueprint class. Open InstancedTest2 level to see it in action.

https://github.com/drichardson/UE4Examples/tree/master/Instanced

Auto-instancing refers to UE4 trying to turn normal UStaticMeshComponents into instanced objects to reduce draw calls without you having to do it yourself using UInstancedStaticMeshComponent. UInstancedStaticMeshComponent works just fine.

Additionally, if you need multple meshes instanced in a single blueprint, you can have multiple UInstancedStaticMeshComponent (or it's hierarchical sub-class), each with a different mesh they are instancing. Here are some screenshots from BP_ActorWithInstancedStaticMesh from the example I mentioned.

image

image

image

image

You missed my point. How are you supposed to be able to instance all occurrences of a mesh, regardless if the mesh falls under the same actor dragged into the scene or not using Blueprints? This sounds more easily solved by using a C++ class to me.

ItsCubeTime commented 3 years ago

@james-baber Sorry for the late reply ':D . I think I will be standing by regarding making any contributions for now, tho its possible I might be looking into this in the future.

The team I work on can put pressure on the engine team to expose some python features in upcoming engine releases, but the turn around is not fast, and is not their first priority.

I think it would be nice if you could make a suggestion to the appropriate team to allow for Blender style object parenting in the level editor as well as a engine-included class/actor that serve as presets for parented objects (so that you can just drag this class/actor into the level and it would then appear in the level as an actor with several other actors parented under it in the outliner). (That could then replace the custom C++ class I first suggested, but give a more robust and engine "native" solution).

I think this is something that would benefit not just for use with the Blender tools but make a fine addition to any level designers workflow regardless of modeling software used.

I would happily make some more in-detail suggestion/ideas on how I think this should be implemented if this was to become reality.

Yes if this is something you would like to work on we welcome PRs. You could open a feature issue for this and layout what would need to be done, like the blender material node to unreal node mappings, and then the python calls needed to instantiate and link the nodes on the unreal side.

Is this something that would already be supported on the Unreal side of things? Modifying a shader (like adding nodes) remotely with a Python script? Im 99% sure you would be able to extract everything one would need using Blenders API.

Another solution would possibly be using Blenders collada or gltf exporter instead of fbx if this is supported by Unreal:

Collada: https://www.khronos.org/files/collada_spec_1_4.pdf#page=245 (Here you can see what PBR definitions are supported by collada, I havent yet checked exactly what is supported on the Blenders collada exporter specifically yet however) https://docs.blender.org/manual/en/latest/files/import_export/collada.html I couldnt quite manage to find any docs regarding what exactly the Collada exporter supports in regards of materials at the time being. Apparently this module is apparently still in a in-dev state (despite that it has been around for quite some time).

glTF 2.0: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html From Blenders docs:

The core material system in glTF supports a metal/rough PBR workflow with the following channels of > information: Meshes Materials (Principled BSDF) and Shadeless (Unlit) Textures Cameras Punctual lights (point, spot, and directional) Animation (keyframe, shape key, and skinning) The core material system in glTF supports a metal/rough PBR workflow with the following channels of information: Base Color Metallic Roughness Baked Ambient Occlusion Normal Map Emissive

Something else that did hit my mind as an alternative solution was if one could extract GLSL from Blender and see if Unreal Engine can make use of it. However I've been digging around a bit on what resources I've managed to find online without any luck. The developer of an old extension that used to be able to export GLSL said "This was developed for BGE that was removed in 2.8 and there's no direct shader access from python in EEVEE so i don't think it's possible to get GLSL shaders at this time.". https://developer.blender.org/T28839 So it looks like this is not possible at the time being.

In terms of shader complexity, I would be happy if just all the PBR values do export just as single floats or textures. Even better would be if the math nodes could be supported as well.

I might be digging deeper in this in the future however Im not certain I will (which is why I shared my findings here in case anyone else would be interested in picking this up).

Thanks for the elaborate response btw.

james-baber commented 3 years ago

@ItsCubeTime ok will add this to the list of python API changes I am trying to get them to ship in a future UE releases.

Is this something that would already be supported on the Unreal side of things? Modifying a shader (like adding nodes) remotely with a Python script? Im 99% sure you would be able to extract everything one would need using Blenders API.

Another solution would possibly be using Blenders collada or gltf exporter instead of fbx if this is supported by Unreal:

I don't know the timeline of a gltf 2.0 importer for unreal, or if there is one currently being developed, but I think the best approach is just to use the bpy.data module. Everything you need to know about your blender material nodes will be there even right down to the 2d transforms of the nodes in the tree and the socket links, so all that could be recreated in unreal. The trick is instantiating the correct nodes in the the unreal material asset. Whether the python already existing to do this is unreal, I do not know, because I haven't done any research or testing. But basically, just play in the unreal python REPL and see if you can find the right call to instantiate the 'matching' blender material node. If not I will added it to the list of python I need added in a future release. https://docs.unrealengine.com/en-US/PythonAPI/index.html

Also if the python is not there, the mapping is still a needed piece. Blender and Unreal share a lot of similar material nodes, but not all will work. So there will need to be a json file that maps blender to unreal material nodes that are indeed 1 to 1.

This is a big project, and I don't know where in the priority stack of things to do this will fall, but I imagine this will be tackled last, so if you want to open an issue with transferring material node trees as a feature, and want to start outlining the details of what you find/what is needed to be done feel free to do so.

james-baber commented 3 years ago

@drichardson And if you feel there would be a way to get object instancing to work via python or pending added python. Feel free to open a feature issue outlining what would be needed, so this can at least get triaged at some point.

james-baber commented 3 years ago

Closing this for now