Website powered by

Takeaways from Making Python Tool

Introduction

I recently finished a Blender and Unreal Engine Python project that aims to streamline the process of exporting and setting up meshes in the engine. I've intended to share this insight for some time now. Not only to serve as a personal reminder for my next Python project but also to offer a learning opportunity for those interested in delving into this field. The python project mentioned in this post can be viewed here: Blender Unreal Workflow Python Tools

1. A tool that does everything?

I must admit that it's tempting to create an all-functional unicorn tool that could possibly result in end of all the game art and design challenges. Except, that doesn't exist. I struggled with this idea for sometime when coming up with a tool to eliminate all workflow woes of efficiently sending meshes from Blender to Unreal Engine. As a game artist, I've had my fair share of challenges when using Blender and Unreal Engine together, but after talking to several other artists, it seemed like the issue was larger than expected.

"I learned that being a Technical Artist entails finding the optimal solution that effectively balances user requirements with project needs."

I started out with the idea of making a "Validation and Export Tool" - two seemingly connected functions that cover a number of issues when dealing with creation and sharing of mesh from DCC application to engine. Common issues when exporting from Blender to Unreal Engine include - dissimilarity in scale units, axis orientation and origin point position when exporting from the former to the latter. This is in addition to common mesh issues, like bad topology, incorrectly facing normals, and overlapping vertices, that further create issues, often realized when brought in engine. This is just tip of the iceberg, the problem escalates very quickly when you're dealing with skeletal meshes or more complex setups.

As one can imagine, targeting multiple use cases can quickly turn chaotic. I was constantly trying to make something that performs both validation and export, but it could not do either of those efficiently without hindering the use of another. Somewhere down the line, I decided to break up my Blender set of tool into two components instead of one super tool - Mesh Validation and Mesh Export, each taking care of its own function. The latter one completes the loop in the form of an Unreal Engine Setup Tool that sets up the exported mesh in the engine. This compartmentalizing of similar but varying functions of the tool allowed me to focus on them independently.

Takeaway: Your tool does not need to solve all and every issue with the processes. Try to identify smaller components that can alleviate workflow issues. Also, this does not imply the tool should sacrifice usefulness for the sake of simplicity. If you find yourself working across several problems, targeting the challenges through different components of the tool could be worth exploring.


2. Artists and Designers are "Users"

I try to bring general UX design principles into practice as much as I can, reminding myself the need to keep meaningful user experience at the heart of the tools I develop. This implies keeping the tool user-friendly and accessible to those without technical knowledge too. The end-user in my case is an artist or designer without little or no knowledge of Python programming. While it is much easier for me to let the user type in a Python command in Unreal Engine console every time they wish to setup meshes and materials, it just doesn't make sense. I may not be making a tool to be used by everyone using Unreal Engine, however the artist using the tool is the end user, and they deserve simple and intuitive experiences.

Is a big button that reads "Import Mesh" always needed to keep the intent of the tool obvious? Not Really. And yes, I can provide more functions if needed, perhaps the ability to specify the meshes and materials in engine, would be useful add-on to this. You may find yourself giving more or less flexibility when it comes to designing user interfaces, but it all comes back to who your "user" is. For the purpose of demonstrating the tool in an academic project, I found it easier to keep it simple and easy to be noticed, since the tool performed singular function. This was also my first introduction to Unreal Engine's Editor Utility Widgets, which I found very intuitive to work with.

Takeaway: Keeping your tools, including functionality and interface user-friendly is necessary. Making users jump through hoops to perform simple tasks is never worth it. 

3. Different APIs can be confusing

Python has numerous applications - one of the reasons why its so popular. However, this also results in having to deal with various APIs with regards to the application in question. While Blender has various resources and even 3rd party tutorials for the Python applications, I found Unreal Engine's Python API to be particularly challenging to navigate. It's understandable given Python's usage inside Unreal Engine is not a popular option, especially when C++ naturally takes precedence as the primary programming language for the game engine. However, python's ease of usage and familiarity is what convinced me to me try it out, and perhaps that could be the case for other developers who are not familiar with C++.

 Here is a small snippet of a function that lets Unreal Engine identify and import a file (in this case, a mesh):

def importAssetsInUnreal():
    ### Simplest way of referring a file directory and using the value
    fileDir = [ " " ]
    assetTools = unreal.AssetToolsHelpers.get_asset_tools()


    ### Create asset import data object ###
    assetImportData = unreal.AutomatedAssetImportData()


    ### Create data attributes for importing ###
    assetImportData.destination_path = '/Game/Meshes/'
    assetImportData.filenames = fileDir


    ### Importing asset using provided data ###
    assetTools.import_assets_automated(assetImportData)

In contrast, Blender's Python API works very differently when used to import or export any file:

def importAssetsInBlender():

    ### Using API's import_scene operator and passing information ###
    bpy.ops.import_scene.fbx(
    filepath='',
    directory='',
    filter_glob='*.fbx',
    ui_tab='MAIN',
    axis_forward='-Z',
    axis_up='Y'
    )


They both have Python at their core of functioning, but they perform differently for the same task. Certainly, its a simplification of the idea, but what it illustrates is that different applications employ and require the understanding of their respective APIs.

Takeaway: The documentation and resources available to you for an application can result in a big difference. It streamlines the processes and opens up gateway to the abundance of resources at your disposal. Taking some time to familiarize yourself with available resources can save hours later. Additionally, I've realized that if the application deserves some learning material, it is wise to contribute to it if you can.

As a result, I am sharing some resources that helped me understand Blender and Unreal Engine Python APIs. In the future, I can make blog posts with specific tutorials for working with both the applications.

Resources:

1. Blender Export Scene Operators - Blender API's export options can seem overwhelming at first, but the sheer number of options at user's disposal is very helpful.

2. Chris Evans Unreal Python Tutorials - Although a little dated, Chris Evans' Python tutorials are immensely useful in understanding the fundamentals.

3. Isaac Oster's Unreal Python Tutorials - Isaac Oster has done helpful work with his trove of Python Unreal resources. One of the few ones on YouTube. He posts them on the Unreal Engine's community page as well.

4. Blender and Unreal Engine Documentation - Elementary yet valuable resources that I keep coming back to. They are your best friends when dealing with both the applications.

Report

Looking through Glass - A Material Study

Material Study: Glass - https://www.artstation.com/artwork/5voJWP

I decided to explore the world of glass materials for a segment of my graduation project. The idea was to explore different ways to render glass for realtime usage in video games. Somehow, I was pulled into rendering techniques and shader optimization, which allowed me to learn much more than just material graph workflow.

Rendering Glass in Video Games

Glass is such a fascinating element in video games. It offers sight in thrilling environments, information in critical PvP matches and contributes to the dynamism of game environments in the most visually compelling ways.

Glass panel in Doom 2016

Unreal Engine Glass

Unreal Engine's capability to make anything look good with minimal effort is commendable. I decided to leverage this as a learning opportunity to familiarize myself with the tools of the material graph. I set out with the follow objectives: 

  • Find different ways to create glass shaders inside the engine
  • Understand optimization and resources for various materials
  • Explore the possibility of a master material creation
  • Come up with creative usage of glass material

I started by combining the wealth of resources on the internet, and my pre-existing knowledge of shaders to come up with a handful ways of producing glass in the game engine. I will be providing some of the helpful resources at the end. 

Testing creation of glass shaders with different variants

I began looking for different ways to create a glass shader in the engine. There are simpler ways of making glass shader. It's as easy as plugging in a low value to the Opacity channel in the material graph, after you have set the material to be shaded translucent. This provides the translucency output in the easiest possible way.


Fresnel

Another common way is to create the illusion of refraction using Fresnel function, which allows the manipulation of the material based on where the viewer is situated. This means that essentially anything in front of the view is rendered with a value of 0, and transitions to the value of 1 in the periphery. This can be used to mask and blend between two values, i.e. how much refraction is perceived at the centre of the material, versus, what is observed around the edges. The fresnel can be modified to update these values, and also tweak how strong the refraction is. 



Fresnel Input


Fresnel-based glass shader

Real-time glass rendering is notoriously heavy on computing, due to the complexity of light calculation. Below is the Shader Complexity of the tested materials, as viewed in Unreal Engine. B2 material falls closer to the end of the spectrum, indicating high complexity. This is due to the fact that the shader is two-sided, and thus require calculations that is reproduced twice for each side. A2 on the other hand is the simplest material - it is essentially an Alpha Cutout Mask, rendering only features outside of the mask.

Instruction count is another useful metric to see how many instructions are being sent to the assembly shader to render the graphic. While it is just an approximation in Unreal Engine, generally speaking, the higher the count means the more expensive the material is. Interestingly, merely enabling the material to be translucent balloons the instruction count to over 200. This is why A2, being a masked material draws the lowest instructions.

Shader Complexity and Shader Instruction Count Overview

Alpha Masking

Alpha masking is one of the cheapest way to render a glass that relies on a binary output, i.e. the glass has either completely transparent or opaque parts. Minecraft makes a great use of this technique for their glass blocks.

Alpha Cutout Glass in Minecraft

This can be taken a step further with a technique known as dithering. It allows the material to create an illusion of varying translucency while still being opaque, through the means of a masking layer to eliminate some pixels. Imagine something like halftone printing technique.

Dithering Gradient

Dithered Alpha Masking - Note the "Noise" in the Material, which is the Dithering Effect

Unreal Engine's material graph provides a material function to replicate the alpha dithering effect easily. I tried it with the Fresnel node to mimic a refractive surface.


Flat Surfaces

There are several reasons why a shader, especially common ones, should be tested across different surfaces. Rendering surfaces in sphere make for an ideal overview as it demonstrates how the curvature interacts with the lighting conditions, however it may not dictate the final use case of a material. The same glass shaders when added to flat surfaces yield completely different output. Interestingly, the glass shader that will ever come into use for gameplay will likely be used for flat surfaces such as windows or a car's windshield, both with little or no curvature. Surfaces like fish bowls or glass orbs are not as frequently encountered in games. The materials do not work in isolation and consideration for the use case needs to determined.

Shader Test Flat Surface

Master Material

When I started with the Glass Master Material, I had to make sure all the components are taken care of - Base Color, Refraction, Roughness, Specularity, and Opacity. On top of that, it should account for other aspects like fresnel-based input, masking where needed and ability to tile textures.

Early Glass Material Test

After the initial setup, I went on adding further enhancements like having the ability to enable and control fogginess, and also a raindrop effect for outdoor scenes.

Master Material Instance Showcase with Parameters

Advanced Glass Master Material Graph

Material Test with Surface Variations

I wanted to test the material for several use cases and came up with some variations that demonstrate different applications using several instances of the master material.

Material Instance Variations

Advanced Glass Material Showcase

Further Explorations

After creating the master material, I wanted to explore the idea of coming up with creative ways to use glass shaders. I began toying around with  the generation of a glass blowing shader - something that mimics the real world process. It's intriguing because the process of shaping glass begins from the material being partly solid to completed rigid. Naturally, the material in engine would also need to follow this rule and heat up and cool down.



Glass blowing process reference

The final scene was rendered in a workshop environment, and illustrates the process where the material heats up, deforms slightly and goes completely opaque before returning to refractive translucency.

Glass Blowing Shader



Glass Blowing Shader Graph

- Thank you for reading! -

Report