Upgrading Promo Art pipeline of NITRO NATION
Hey there! I am Ramil Roosileht, senior tech artist working at CM Games. In this article I’d like to tell you about how I updated our pipeline for creating various promotional artwork for Nitro Nation. TL;DR: by switching from Unity to Blender
The new approach made it possible to not only increase the quality of the artworks, but also create them a lot faster. Couple examples for comparison:
The old pipeline
Earlier promo-art was mostly created using screenshots made in Unity Editor. Mobile shaders and simple lighting worked fine on a small smartphone screen, but didn’t provide a solid enough foundation for making beautiful artworks.
This is how a Unity scene would look from the Editor. If you’d like to change anything, like having a custom lighting setup or moving around some objects, you’d then need to wait for for static lighting to re-bake, making the whole process extremely tiresome.
Promo art after compositing and overpainting.
Drawback of the old approach:
Searching for alternatives
At first I tried to improve the existing workflow. For that, I’ve added a default Unity Post-Processing Stack, because it allows us to work with post processing in editor mode without launching the game. Then I replaced our usual optimized shaders with standard PBR ones, to get better shading and a full texture package.
All these changes improved the overall quality a little bit, but scene setup also took longer, because of materials alterations and light baking. Also, some of the post processing effects like AO and SSR required deferred rendering and were unavailable with our forward rendering without additional work required to change it.
To continue enhancing this, I would need to create a separate branch for the project and globally change its rendering. Then this branch would need to be maintained and kept up-to-date with the master branch. Because of that I started looking for other options.
The task at hand: Build a promo art pipeline that would focus on the artists and the software they use. Ideally this would require using a popular and free 3D package that has advanced rendering features.
My options were as follows:
Blender has a few advantages over other options:
Next thing would be to handle import and export to Blender. In my case the cars need to be transferred with the textures, keeping the exact configuration they’ve had in the game.
Car source files are stored as FBXs inside the project and have a whole range of car parts inside of them. Using them for renders as-is is inconvenient - you’d need to sort out what parts in what configuration you’re gonna use yourself. But? the cars that are loaded when the game is running are already configured, you just need a way to save them. The simplest way I’ve accomplished this was by adding an FBX Exporter package to our project. It supports Binary and ASCII FBXs and can be called from scripts or from the editor. Resulting files also keep their prefab hierarchy and links to the textures.
Now that we have the export sorted out, we can import the models in Blender. But right now the car looks even worse than before, because FBX is not successful at transferring material parameters, especially when they are used with custom shaders.
Freshly imported cars lack proper materials and their textures are set up incorrectly. We can’t use them for promo art just yet.
To make the car look correct, following needs to be done:
Doing all of these by-hand would be a huge time sink, but I can automate most of the stuff using a Python API. All that’s left for an artist would be to check the car and start using it.
Writing Blender scripts
First of all, always good to scroll through the documentation : https://docs.blender.org/api/current/info_quickstart.html
Easiest way to start writing scripts is using Blender’s text editors.
There are 3 windows provided in the scripting tab:
领英推荐
Making-of Nitro Nation Car Converter addon
Let’s recap what it needs to do:
I am going to showcase the main functions I’ve made when writing the addon:
Function to import a collection from a library blend file:
def importColl(collectionName):
//Needs import os in a header to access file directory
????path=os.path.dirname(__file__) + "/collections/library.blend\\Collection\\"
????bpy.ops.wm.append(filename=collectionName, directory=path)
Function to delete unused objects by their name:
def cleanUp():
//List of names to search
????RemoveStrings = ["Gear*","*flare*","UI*"]
//Make sure no objects are selected
????if? bpy.context.view_layer.objects.active != None:
????????bpy.context.active_object.select_set(False)
????bpy.ops.object.select_all(action='DESELECT')
//Select all objects that correspond to names in the list and delete them
????for str in RemoveStrings:
????????bpy.ops.object.select_pattern(pattern=str)
????????print (str)
????bpy.ops.object.delete(use_global=False)
????bpy.ops.object.select_all(action='DESELECT')
Function to fix texture parameters:
def fixImport():
//Change alpha mode for all textures except seams texture
????for tex in bpy.data.images:
????????if "seamTex" not in tex.name:
????????????tex.alpha_mode = 'CHANNEL_PACKED'
????for mat in bpy.data.materials:
????????if 'Seam' in mat.name:
????????????continue
//Change basic shader values for car rims
????????if 'Disk' in mat.name:
????????????mat.node_tree.nodes["Principled BSDF"].inputs[6].default_value = 1
????????????mat.node_tree.nodes["Principled BSDF"].inputs[9].default_value = 0.25
????????if 'tyre' in mat.name:
????????????mat.node_tree.nodes["Principled BSDF"].inputs[7].default_value = 0.25
????????????mat.node_tree.nodes["Principled BSDF"].inputs[9].default_value = 1
//Labels require Alpha Clip as they are decals. Any other material with the texture has an unneeded link to its textures alpha channel. This link needs to be removed.
????????if 'ables' in mat.name:
????????????mat.blend_method = 'CLIP'
????????????print (mat.name," set to clip")
????????????mat.use_nodes = True
????????????mat_node = mat.node_tree.nodes
????????else:
????????????mat.use_nodes = True
????????????mat_node = mat.node_tree.nodes
????????????for node in mat_node:
????????????????if "Image Texture" in node.name and node.outputs[1].links != None:
????????????????????for link in node.outputs[1].links:
????????????????????????mat.node_tree.links.remove(link)
if mat.blend_method == 'BLEND':
????????????if mat.name not in ['Glass', 'Glass_Clear']:
mat.blend_method = 'OPAQUE'????
Function that replaces an existing material with a newly imported one. Is packed into try/except since it is possible to have a car that doesn’t have one of the materials specified, like carbon.
def applyMaterial(objectName, searchPattern):
???try:
????????source = bpy.context.scene.objects[objectName]
????????bpy.context.view_layer.objects.active = source
????????source.select_set(True)
????????bpy.ops.object.select_pattern(pattern=searchPattern)
????????for ob in bpy.context.selected_objects:
????????????if "able" in ob.name:
????????????????ob.select_set(False)
????????bpy.ops.object.make_links_data(type='MATERIAL')
????????bpy.ops.object.select_all(action='DESELECT')
????except:
//See what materials have failed to apply
????????print(objectName,"- failed.")
????????pass
The rest of the scripting consists mostly of using these functions and adding the addon interface. After the installation a new panel appears with some buttons. There is also an additional button for spawning a racer's rig into the scene. He can be used to have someone sitting in a car or as a scale dummy when modeling.
Making a promo art using the new pipeline
Let’s try it out by looking at the creation of a loading screen with Ford Mustang RTR-X. Initially the requirements aren’t strict - the main focus in the shot should be on a car while it is drifting around. Since it is a loading screen, the size needs to be big enough and the composition should crop well to all main aspect ratios - 18:9, 16:9, 4:3.
Spawn a car for the export. This is how it looks in a garage.
This is the same car after being brought to Blender and converted using the addon.
Next I am going to link the car to a file with the race track and set up a camera angle. At this point it is beneficial to make a quick Viewport Render to see whether the composition fits the requirements. After that I’m adding an OpenVDB smoke sim and animating the car with the camera for a few frames to get a nice motion blur effect going. I’ve found that when doing it in Blender it looks a lot more believable than when you try to fake it in photoshop later.
After a bit of compositing and color correction, the art is done!
Advantages of this approach
When using Blender for promo art creation, artists can employ a wide array of features, not usually accessible to a game engine. For example:?
Feedback about the new pipeline
The new pipeline for art creation made artists work drastically easier and freed their time for other tasks. Now they don’t need to waste their time hand drawing over screenshots and can work more like a photograph would - think how to better setup lights in a scene, try different camera angles and so on. Iteration time has also sped up considerably, since renders only require minimal post-processing - usually a simple Camera Raw filter is enough so you can already crop it for required ratios and prepare texts.
Marketing teams' jobs also became easier - they are able to ask for more art if there is a big sale coming and the quality won’t suffer. If any adjustments need to be made, all you have to do is re-render the picture and replace a smart object in Photoshop. No redrawing required!
Tool development, even on a smaller scale, still noticeably raises work efficiency and gives the team an ability to focus on more creative tasks. The pipeline described in the article has been in use since 2020 and has been thoroughly tested by the art team. Even with the frequent Blender updates, the addon usually doesn’t require any changes when switching to a new version.
Product development with Unity | .Net | Games | Mobile Apps | CTO | Solution architect | Engineering manager | Team lead | Tech lead | Team management | Agile | Startups
2 年great job ??
Engineering Manager at Microsoft
2 年Good job!