getavalon / core

The safe post-production pipeline - https://getavalon.github.io/2.0
MIT License
213 stars 48 forks source link

unreal engine support #498 #517

Closed antirotor closed 4 years ago

antirotor commented 4 years ago

This is implementation of #498.

Introduction

Unreal Engine can be used for many different things from its obvious use in game development to render/previz tool in movie production. Its architecture is somehow different then in most common DCCs where we work within project directory holding relevant stuff and using scene files that produce publishable output like models, renders, etc. As Unreal is first of all game engine, project is more interlinked then just bunch of directories and scene files doesn't exists at all. Instead we have levels and those can be considered as possible versioned scene files. I suppose that most common use of Unreal will be in context of sequence/episode or game itself containing all assets under it - in movie, every unreal level can be scene in sequence or even shot.

Implementation

This is DRAFT pull request to allow discussion about particular implementation details.

Setup

Unreal has no way to create main menu entries with Python. For that I've created plugin that creates basic Avalon menu entries and I am referencing it in this code. This plugin calls c++ methods on class and those are overridden during Unreal startup in python Content/Python/init_unreal.py

https://github.com/antirotor/avalon-unreal-integration/blob/f21b2f4830559cf33cb68e766f2c1d93a2c4291e/Content/Python/init_unreal.py#L8

Those methods should call relevant code from this integration to show Avalon dialogs, etc.

So far I've implemented functions in lib to find installed Unreal Engines and to create projects. Those projects in Unreal are set of directories and .uproject file that is actually a JSON file. In this file, we can specify what built-in and external plugins our project will use so I took opportunity and placed there code to enable Python plugin and also install (copy it to new project directory) Avalon Integration plugin if found on set AVALON_UNREAL_PLUGIN env variable. This could be extended in future to make use of TOOLS and other stuff specified in configs.

Work to be done

Containers

Find out how to containerize assets loaded in Unreal. This can be done in three ways:

Unreal supports creating arbitrary metadata on each asset with Python. This looks to me like the most promising way. Other possible ways would be our own UActor descendant class wrapping imported assets, or perhaps adding Blueprint component to assets holding information?

Functions to show dialogs

As mentioned above, we need functions to be called from integration plugin to show dialogs, but those should be easy enought to implement.

Workio

I am quite not sure what to do with workio part as there is no scene file nor ability to open one. Perhaps work with levels can be tweakend into existing workio api.

Note, this is still non-functional and heavy in development.

antirotor commented 4 years ago

So far I've made progress in project support code. This is included in lib.py but should be handled by config and is there mainly for reference. How do we do it in pype now: just before unreal editor is launched on specific task, hook is called and checks if there is Unreal project in AVALON_WORKDIR. If not, it creates one using create_unreal_project() and prepare_project() in lib. Those two functions:

There are few caveats so far:

Unreal needs Visual Studio to work

This is because of Avalon Integration plugin distribution as source code. Overhead of compiling and distributing plugin binaries is shifted to the user :)

Unreal limits project name format

Project name in Unreal must be less then 20 characters and must not start with non-alpha character as its name is used inside Unreal code as variable name in multiple places.

I don't like the idea of writing this hardcoded source code from python, but I wasn't able to find other way. There can possibly be way to run some Unreal generator creating those files in more safe way.

cameronpd commented 4 years ago

There are few caveats so far:

Unreal needs Visual Studio to work

This is because of Avalon Integration plugin distribution as source code. Overhead of compiling and distributing plugin binaries is shifted to the user :)

I don't know what's industry standard practice, but I know in our indie game division, artist don't have visual studio installed on their computers. The only person I know for certain that has visual studio installed is the leader programmer as he compiles the builds.

antirotor commented 4 years ago

True, but from Avalon point of view it shouldn't matter. That code in lib is there mainly for reference and how you create and setup project is on avalon config implementation. In Pype I did it so you have options to either point with preset to compiled plugins so project won't need compilation or point to the sources. I agree that with visual studio it is mainly for development but can be useful until unreal implementation in avalon is stabilized.

antirotor commented 4 years ago

So I've tweaked code in lib.py a little bit so C++ project gets created only if Binaries and Intermediate folders are not present in installed plugins. So if we provide compiled binaries for running Unreal Engine version then normal project get created and that doesn't need Visual Studio installed.

antirotor commented 4 years ago

I've made more changes:

Support for containers

Unreal doesn't have concept of groups or sets in its Content Browser, assets there are organized in folder structure. Unfortunately we cannot add metadata to these directories.

So I've made two new Blueprint classes - AvalonContainer and AvalonPublishInstance. They are almost same. They are created by avalon in containerise() or other places at the folder grouping assets. For example - we have family Prop consisting of static mesh Foo and its material Bar. Selecting those and clicking Create ... -> Prop will move them from wherever they are to /Game/modelingPropFoo (or whatever it's subset name is) and under it it will create instance of AvalonPublishInstance:

/Game/modelingPropFoo
               /modelingPropFoo (AvalonPublishIntance)
               /Foo (StaticMesh)
               /Bar (Material)

It will imprint metadata on AvalonPublishInstance - and that is whats returned by ls(). There is also functionality implemented in both Blueprint classes to track all assets under directory where instance of this class is, so modelingPropFoo will have live list of assets under /Game/modelingPropFoo. This is right now just shotcut because unreal api has ability to list assets at some path, but its foundation for later more advanced usage.

Folder color

We can color code directories in Content Browser to help visualize types of Avalon containers or publish instances. With few caveats I am afraid - setting color will have visible result only after Unreal Editor is restared as this information is written into project config ini file. I couldn't find a way to "refresh" it.

Most of the code reflect changes in antirotor/avalon-unreal-integration. Note that we'll move this repository to pypeclub/avalon-unreal-integration.

Still need more work and testing.

antirotor commented 4 years ago

Basic documentation

Disclaimer

This is now in basic working state. Here is a little bit of documentation take from my Pype PR note. As Pype is now fully opensourced, you can see details about Pypes parts there but note that no code here has any dependency in Pype. Avalon bits are identical, project generation code is there also, the only difference is that in Pype there is example implementation of creators and loaders and demo pipeline for exporting static meshes from Maya. I apologize for all those Pype references but as it is quite a long text I didn't have enough energy to edit it 😩

Requirements

Installation in Unreal

You need to compile Unreal Editor Avalon Integration plugin for your Unreal Engine version. For that you need Microsoft Visual Studio 2017 (Community Edition is 👌 ). You can either compile it manually, or just clone it somewhere and then set AVALON_UNREAL_PLUGIN to point there. This can also be set in pypeclub/pype-config in environments/unreal_4.24.json on line 2. Then during Unreal project creation when starting Unreal from ftrack task, Pype will detect presence of Binaries and Intemediate folders in plugin directory at AVALON_UNREAL_PLUGIN. If found, they will be copied to new project then and Visual Studio is not needed. Otherwise project will be set as C++ project and it will compile everything during first launch.

It will automatically enable required plugins PythonScriptPlugin and EditorScriptingUtilities.

Implementation

Implementation is multi-part. Avalon Core part implements support for loading, creating, managing and publishing instances. Pype part takes care of project setup, Unreal launching and basic pipeline for publishing StaticMesh from Maya and loading, managing and creating publish instance in Unreal.Avalon Integration Plugin is enabling Avalon in Unreal - it provides menu to control avalon functionality and provides other support functions for bridging Unreal and Avalon. And finally pype-config is providing basic support for creating correct environment.

Avalon Integration Plugin

:warning: Python Scripting in Unreal Editor is still VERY experimental indeed. Things can (and probably should) change

Menu

This is C++ and Python code connecting Unreal Python API and Avalon Core API. Unreal doesn't support creation of new main menu items from Python so this plugin is defining new Blueprint class doing just that. Callback functions for this menu are implemented in Python part (in Content/Python/init_unreal.py) and they themselves are referencing corresponding functions in avalon-core host integration.

unreal-Annotation 2020-03-16 224046

Containers

This plugin is also providing two "container" BP classes - AssetContainer and AvalonPublishInstance container. Reason behind those two is that you cannot add metadata to folders in Unreal Editor Content Browser - and that is the only way to group assets together there.

So loading stuff from avalon will create folder with subset name, put content in it and also create AssetContainer class asset there to hold metadata.

unreal-2

There are two reasons for this: first, it holds metadata on it needed for Avalon to keep track of assets and second - it helps to easily find this container. Unreal project can have thousands of assets and iterating through them can be time consuming. But finding assets of only specific class type is much faster.

Those two classes tracks all changes in directory they reside in and provide live list of assets they are "containing" for script or Blueprint use.

unreal-3

Other

This plugin is also exposing some C++ API not available yet in Python API, implemented as UAvalonLib in C++ and AvalonHelpers in Python. There is currently only one function - set_folder_color() that can be used to set folder colors 😄 that can be normally done from UI. Caveat is that for color change take place, editor must be restarted.

Pype Integration

As work in Unreal Editor is quite different then in other DCCs there must be different approach to its support. In Unreal, there are no work scenes as files. Instead we work directly in self-contained project folder. So running Unreal Editor in specific context must include environment setup, project management and Unreal Engine version support.

Determining Unreal Engine version

Pype can autodetect installed Unreal Engine versions (at least on Windows). You can then choose per project/task what version you wish to use. This is done by enabling corresponding Avalon application in ftrack.

unreal-4

Project Setup

When launching Unreal Editor for given context, project must be prepared before Engine itself is run:

⚠️ Unreal Python Engine: This plugin may not support latest Unreal Engine versions
📔 You can also trigger C++ project by setting dev_mode in presets
Example implementation

This is pre-launch hook file of Pype preparing Unreal project before launch. It is using same functions as they are in project.py in this PR:

https://github.com/pypeclub/pype/blob/feature/PYPE-617-UE-basic-integration/pype/hooks/unreal/unreal_prelaunch.py

Avalon and Pyblish plugins

This includes basic support of Static Meshes pipeline. You can create and publish Static Meshes from Maya and load them into Unreal. There is simple validation for correct naming and checking for world orientation etc. This is not by far complete pipeline and serves as demonstration for implementing other, more advanced stuff.

Avalon Core Integration

This implements necessary host specific API in Avalon Core to support it and its tools. Mainly creating containers, imprinting them with data and discovering them.

Caveats

tokejepsen commented 4 years ago

Just wanted to say great work on this!

antirotor commented 4 years ago

This has been contaminated by Pype. I'll close this one and I'll make another PR with vanilla Avalon Core.