Upgrading Promo Art pipeline of NITRO NATION

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:

No alt text provided for this image
No alt text provided for this image

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.

No alt text provided for this image

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.

No alt text provided for this image

Promo art after compositing and overpainting.

Drawback of the old approach:

  • Painting over and adding detail on top of screenshots took a lot of time from the artists. Because of that, at most one artist could make only 1,5 artworks per day.
  • The resulting artworks didn’t look as good as competition from other, newer projects.

No alt text provided for this image

  • It was really difficult to change things after the paint over process took place. If we needed to adjust the angle, or change the car, we’d need to start over.
  • Sharing sources between people was difficult. You would need to pack the whole scene with objects, textures and materials into a unity package, then get rid of any dependencies that you don’t need.

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:

  • Unreal Engine - Only for rendering, would need to search for premade assets.
  • SketchUp - Only for modeling, requires plugins for rendering.
  • Blender - Fully featured and allows for both content creation and rendering.

Blender has a few advantages over other options:

  • Completely free. 2D artists usually don’t have a Maya\Max license
  • Open Source and features a fully documented API. A lot of space for scripting
  • Constant updates and improvements. One of the most active FOSS communities
  • Lightweight. The installer is around 200mb and has a portable option. Supports Windows/Mac/Linux.

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.

No alt text provided for this image

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:

  1. Fix texture alpha usage. Transparent tires and radiator as well as some other parts indicate that alpha is being used where it shouldn’t, so ideally only car labels should be using it, and everything else should be opaque. (except stuff like glass)
  2. Create new materials to replace corrupted ones. Things such as car paint, chrome, glossy and rough plastics, rubber and glass etc..
  3. Assign newly created materials to correct parts of the car. In my case it’s pretty simple because the naming hierarchy already has materials names inside.
  4. Clean up unused anchors and objects to make the hierarchy more readable.
  5. Visually compare whether car looks similar to the game representation

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

No alt text provided for this image

Easiest way to start writing scripts is using Blender’s text editors.

There are 3 windows provided in the scripting tab:

  1. Python Console. Simple console that has an auto-fill option and a couple of shortcuts to save time. Good for checking out available operators.
  2. Info. Log, that writes most of users actions as Python operators, thus making it possible to copy-paste those directly into the script.
  3. Text Editor. A notepad-like thing where you can make text files, write and also run scripts. Also has a number of useful templates to choose from, in the “Templates” tab. To run a script, press Play ?.

No alt text provided for this image




Making-of Nitro Nation Car Converter addon

Let’s recap what it needs to do:

  • Delete unnecessary objects
  • Load a library of predefined materials
  • Replace current car materials with newly loaded ones
  • Fix alpha channel mode of cars textures
  • Summon a rigger driver character

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
        
No alt text provided for this image

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.

No alt text provided for this image

Spawn a car for the export. This is how it looks in a garage.

No alt text provided for this image

This is the same car after being brought to Blender and converted using the addon.

No alt text provided for this image

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.

No alt text provided for this image

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:?

  • Switch between a rasterizer Eevee or precise path-tracer Cycles engine
  • Shading Nodes allow for complex material authoring
  • “Real” Motion blur (generated by moving a camera with a car in a scene)
  • OpenVDB volumetrics for fog, smoke or fire
  • Geometry Nodes to render point clouds (raindrops or dust on a car)
  • Light Groups to easily change light influence without re-rendering
  • Various Render Passes for final compositing?

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.

Andrei Korober

Product development with Unity | .Net | Games | Mobile Apps | CTO | Solution architect | Engineering manager | Team lead | Tech lead | Team management | Agile | Startups

2 年

great job ??

回复
Vlad Sviatetskyi

Engineering Manager at Microsoft

2 年

Good job!

回复

要查看或添加评论,请登录

Ramil Roosileht的更多文章

  • 5 Obscure Features of PCG in UE5

    5 Obscure Features of PCG in UE5

    Procedural Generation Framework, or PCG for short, is a great little system which first shipped in Unreal 5.2 and…

    4 条评论

社区洞察

其他会员也浏览了